00 윈도우 프로그래밍 팁

원문 :  http://kkamagui.springnote.com/pages/347952

 

들어가기 전에...

 

각종 윈도우 팁들 - Debug Lab

 http://www.debuglab.com/knowledge/

 

WinDBG의 심볼 경로 설정

SRV*c:\websymbol*http://msdl.microsoft.com/download/symbols  -->

 

VC에서 메모리 관련 디버그 명령

INIT_CRTDEBUG(); <== 메모리 누수 모니터링 시작
BREAK_ALLOC(X); <== 메모리 X 블럭 할당시 Break

 

VC에서 Alt-F4 막기

Alt+F4 키와 같은 메세지를 처리해주기 위해서 CWinApp 함수의 PreTranslateMessage() 를 override 해서 아래의 코드를 넣어 주면 된다.

  1. if(pMsg->message == WM_SYSKEYDOWN && pMsg->wParam == VK_F4)
    {
        return TRUE;
    }

 

 

익스플로러가 죽어도 트레이아이콘에 계속 상주시키기

  1. // 메시지 등록 과정
    UINT g_uShellRestart;
    g_uShellRestart = RegisterWindowsMessage( "TaskbarCreated" );

    // Message Map 에서
    ON_REGISTERED_MESSAGE( g_uShellRestart, OnTrayShow )

    // 메시지를 처리합니다.
    LRESULT CMyDlg::OnTrayShow( WPARAM wParam, LPARAM lParam )

       // TrayIcon을 다시 보여줍니다. ShowTray는 Tray를 보여주는 함수입니다.
       m_Tray.ShowTray();
    }  -->

 

 

 Variable Argument(가변 인자)

  1. // crt_vsprintf.c
    // This program uses vsprintf to write to a buffer.
    // The size of the buffer is determined by _vscprintf.

    #include
    #include

    void test( char * format, ... )
    {
       va_list args;
       int len;
       char * buffer;

       va_start( args, format );
       len = _vscprintf( format, args ) // _vscprintf doesn't count
       + 1; // terminating '\0'
       buffer = malloc( len * sizeof(char) );
       vsprintf( buffer, format, args );
       printf( buffer );
       free( buffer );
    }

    int main( void )
    {
       test( "%d %c %d\n", 123, '<', 456 );
       test( "%s\n", "This is a string" );
    }

 

 

윈도우에서 Command Line Argument 얻기

 argc = __argc, argv = __argv 로 얻으면 된다.

 

 

윈도우 공유 폴더 로그인 시 이상한 계정으로 로그인 되는 경우

 관리도구->사용자계정->좌측 상단의 네트워크 연결관리 에서 서버와 계정을 추가한다.

 

 

툴팁 생성하기

 툴팁 생성 코드

  1.     m_clToolTip.Create( this, WS_VISIBLE | WS_BORDER );
        m_clToolTip.AddTool( this, "" );
        m_clToolTip.SetDelayTime( 100 );
        m_clToolTip.Activate( TRUE );

 

 툴팁 표시를 위한 메시지 릴레이 코드

  1. /**
        Enter와 Esc로 인한 종료를 막는다.
    */
    BOOL CSubPartition::PreTranslateMessage(MSG* pMsg)
    {
        if( pMsg->message == WM_KEYDOWN )
        {
            if( ( pMsg->wParam == VK_ESCAPE ) ||
                ( pMsg->wParam == VK_RETURN ) )
            {
                return TRUE;
            }
        }
  2.     // ToolTip 표시를 위해 메시지 릴레이 설정
        m_clToolTip.RelayEvent(pMsg);
        return CDialog::PreTranslateMessage(pMsg);
    }

 

 

Shell Execute로 프로그램 실행하기

 

  1. BOOL ExecuteProgram( String FileName, String Params, INT Flag )
    {
      SHELLEXECUTEINFO execinfo;
     
      // 실행을 위해 구조체 세트
      ZeroMemory( &execinfo, sizeof(execinfo) );
      execinfo.cbSize = sizeof(execinfo);
      execinfo.lpVerb = "open";
      execinfo.lpFile = FileName.c_str();
      execinfo.lpParameters = Params.c_str();
      execinfo.fMask = SEE_MASK_FLAG_NO_UI SEE_MASK_NOCLOSEPROCESS;
      execinfo.nShow = SW_SHOWDEFAULT;
     
      // 프로그램을 실행한다.
      int r = (int)ShellExecuteEx( &execinfo );
      if ( r == 0 ) return ( false );
     
      // 만약 Sync 플랙이 세트되었으면,
      // 실행이 종료될 때까지 기다린다.
      if ( Flag == 1 )
      {
        DWORD ec;
        do
        {
          GetExitCodeProcess( execinfo.hProcess, &ec );
          Application->ProcessMessages();
        }
        while ( ec == STILL_ACTIVE );
      }
     
      return ( true );
    }

 

 Open URL로 웹 연결하기

CInternetFile* pFile = NULL;
CInternetSession InetSession;
 
try
{
  pFile = (CInternetFile *)InetSession.OpenURL( "URL 주소 : http://???" )
}
catch(CInternetException *pEx)
{
  pFile = NULL;
  pEx = NULL;
  AfxMessageBox( "OpenURL Excption Error!" );
}
 
CString strData;
 
if( pFile )
{
  CString strTemp;
  pFile->SetReadBufferSize( 4096 );
 
  while( true )
  {
    if( pFile->ReadString( strTemp ) )
    {
      strTemp += "\r\n";
      strData += strTemp;
    }
    else
    {
      break;
    }
  }
}
else
{
  AfxMessageBox( "OpenURL pFile is NULL!!" );
}
 
MessageBox( strData );

 

윈도우에서 F1 키 막기 또는 기능 변경하기

 APP의 아래부분을 막거나 변경한다.

  1.  ON_COMMAND(ID_HELP, CApp::OnHelp)

 

 

DLL의 함수 Export시 정해진 이름으로 Export 하기

 DLL의 함수를 그냥 Export 하면 함수 이름 그대로 Export 되지 않고 기타 정보가 더 붙는다. extern을 사용하면 어느정도 해결되지만 확실한 해결책은 def 파일을 이용하는 것이다. 아래와 같이 쓰면된다.

  1. LIBRARY MyDll
    EXPORTS
       Function1=Function1
       Function2=Funciton2
  2.    Data1                 DATA <== 데이터를 외부로 Export 할때
  3.    Function3             @1   <== 서수를 같이 Export 할때
  4.    Function4             @2   NONAME  <== 서수로만 Export 할때, 함수 이름 포함 X
  5.    Function5                  PRIVATE <== lib 파일에 Function5에 대한 내용 제외, DLL에는 있음

 

파일(File) 및 라인(Line) 관련 매크로(Macro)

  • __FILE__ : 해당 파일 이름으로 대체
  • __LINE__ : 해당 라인 번호로 대체

 

  1. printf( "%d %d", __FILE__, __LINE__ );

 

printf 직접 구현하기

 C/C++의 Calling Convention을 보면 Stack에 파라메터를 넘긴다. 이것을 이용하여 Variable Argument List를 찾아서 넣는 방식이다.

  1. /**
     임의로 만든 printf 함수
      printf 함수의 간략버전
    */
    void kPrintf( char* pcFormat, ... )
    {
        DWORD* pdwArg;
        char vcBuffer[ 1024 ];
        int iBufferIndex;
        int iFormatIndex;
        char* pcString;
        int iLength;
  2.     // 2번째 Argument를 pdwArg가 가리키고 있다.
        pdwArg = ( DWORD* ) &pcFormat + 1;
        iBufferIndex = 0;
        iFormatIndex = 0;
  3.     // 문자열 끝까지 한다.
        while( pcFormat[ iFormatIndex ] != '\0' )
        {
            if( pcFormat[ iFormatIndex ] != '%' )
            {
                vcBuffer[ iBufferIndex ] = pcFormat[ iFormatIndex ];
                iFormatIndex++;
                iBufferIndex++;
                continue;
            }
  4.         iFormatIndex++;
            switch( pcFormat[ iFormatIndex ] )
            {
                // 16진수 출력
            case 'X':
            case 'x':
                // 10진수 출력
            case 'd':
                kDToA( vcBuffer + iBufferIndex, *pdwArg );
                iBufferIndex += 8;
                iFormatIndex++;
                pdwArg++;
                break;
  5.             // 문자열 출력
            case 's':
                pcString = ( char* )( *pdwArg );
                iLength = strlen( pcString );
  6.             kMemCpy( vcBuffer + iBufferIndex, pcString, iLength );
                iBufferIndex += iLength;
                iFormatIndex++;
                pdwArg++;
                break;
     
                // 문자 출력
            case 'c':
             vcBuffer[ iBufferIndex ] = *pdwArg & 0xFF;
             iFormatIndex++;
             iBufferIndex++;
             pdwArg++;
             break;
             
                // % 출력
            case '%':
                vcBuffer[ iBufferIndex ] = '%';
                iFormatIndex++;
                iBufferIndex++;
                break;
           
                // 그외 기타
            default:
                vcBuffer[ iBufferIndex ] = pcFormat[ iFormatIndex ];
                iFormatIndex++;
                iBufferIndex++;
                break;
            }
        }
        vcBuffer[ iBufferIndex ] = '\0'; 
       
        // 내부 출력함수 이용
        kPrintfInternal( vcBuffer );
    }

 

 

조사식 창(Watch)에 에러(Error) 내용 보기

 아래와 같이 입력하면 에러코드와 내용을 볼 수 있다.

  1. @err,hr 

 

VC 6.0에서 XP 스타일 적용하기 

원문 :  http://blog.naver.com/kisatsg?Redirect=Log&logNo=20004074897

① 다음 내용을 편집하신후에 프로젝트 아래의 res 디렉토리에 ApplicationManifestXMLFile 파일로 저장합니다.

 

./res/ApplicationManifestXMLFile

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
                 manifestVersion="1.0">
<assemblyIdentity
    version="1.0.0.0"
    processorArchitecture="X86"
    name="Microsoft.Windows.YourApplication"
    type="win32"
/>
<description>YourApplication</description>
<dependency>
    <dependentAssembly>
        <assemblyIdentity
            type="win32"
            name="Microsoft.Windows.Common-Controls"
            version="6.0.0.0"
            processorArchitecture="X86"
            publicKeyToken="6595b64144ccf1df"
            language="*"
        />
    </dependentAssembly>
</dependency>
</assembly>
② resource.h 에 아래 두줄 추가
#define IDR_MANIFEST  1
 #define RT_MANIFEST  24
③ .rc2 파일은 거의 손 안대시죠? 그 파일안에 다음 내용을 쳐 넣습니다.
// Add manually edited resources here...
IDR_MANIFEST RT_MANIFEST MOVEABLE PURE
             "res\\ApplicationManifestXMLFile"
④ Instance 시작 파일에 다음 내용을 쳐 넣습니다.
BOOL MoneyApp::InitInstance()
{
  InitCommonControls();    // initialize common control library
  CWinApp::InitInstance(); // call parent class method

#ifdef _AFXDLL
  Enable3dControls();      // Call this when using MFC in a
                           // shared DLL
#else
  Enable3dControlsStatic(); // Call this when linking to MFC
                            // statically
#endif

  // the rest of the code
}
이상입니다. 모 사실 ④번은 안해도 되는데, 원저자가 하라길래 했지요. ^^;

 

 

Tray Icon 관련 

1.Add Tray 

  1.  void CMainFrame::AddSysTray()
    {
     NOTIFYICONDATA data;
     data.cbSize = sizeof(NOTIFYICONDATA);
     data.hWnd = m_hWnd;
     data.uID = IDR_MAINFRAME;
     data.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
     data.uCallbackMessage = WM_SYSTRAYCLICKED;
     data.hIcon = AfxGetApp()->LoadIcon( IDR_MAINFRAME );
     strcpy(data.szTip , VERSION);
     Shell_NotifyIcon( NIM_ADD, &data );
    }

 

2.Delete Tray

  1. void CMainFrame::DeleteSysTray()
    {
     NOTIFYICONDATA data;
     data.cbSize = sizeof( NOTIFYICONDATA );
     data.hWnd = m_hWnd;
     data.uID = IDR_MAINFRAME;
     Shell_NotifyIcon( NIM_DELETE , &data );
    }

 

3.메시지 처리 

  1. LONG CMainFrame::OnSystrayClicked( WPARAM wParam , LPARAM lParam )
    {
     CYesNoDlg dlg;
  2.     switch( lParam )
     {
     case WM_LBUTTONDBLCLK:
      //::ShowWindow( m_pVisibleWnd->m_hWnd , SW_RESTORE );
      m_pVisibleWnd->ShowVisibleFrame();
      TRACE("에루 버튼\n");
      break;
     case WM_RBUTTONDBLCLK:
      TRACE("아루 버튼\n");
      if( dlg.DoModal() == IDOK )
      {
       PostMessage( WM_CLOSE , 0 , 0 );
      }
      break;
     }
     return TRUE;
    }

 

4.태스크바가 다시 생성되었을 때 재등록

  1. LRESULT CMainFrame::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
    {
     // 만약 테스크바가 제시작 되었으면
     // 익스플로어가 한번 죽었던 것이므로..
     // 새로 Tray에 더한다.
     if( message == RegisterWindowMessage("TaskbarCreated") )
     {
      AddSysTray();
     }  
     return CFrameWnd::DefWindowProc(message, wParam, lParam);
    }

 

다이얼로그 기반 프로그램에서 처음 시작시 다이얼로그 안띄우기 

 WM_WINDOWPOSCHANGING 메시지를 이용한다. 이 메시지는 Dialog 메시지에는 없으므로 클래스 위져드에서 메시지 쪽에 메시지 필터를 "Window"로 바꿔줘야 나온다.

  1. void CHidDlgDlg::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
    {
        CDialog::OnWindowPosChanging(lpwndpos);
      
        // TODO: Add your message handler code here
        if(m_bShowFlag)
            lpwndpos->flags |= SWP_SHOWWINDOW;
        else
            lpwndpos->flags &= ~SWP_SHOWWINDOW;
  2. }
  3. BOOL CHidDlgDlg::ShowWindowEx(int nCmdShow)
    {
        m_bShowFlag = (nCmdShow == SW_SHOW);
        return (GetSafeHwnd()) ? ShowWindow(nCmdShow) : TRUE;
    }
  4. 출처 : Tong - luster님의 Tip통

 

 

윈도우 핸들(Window Handle, hwnd)로 클래스 이름(Class Name) 얻기

  1. int GetClassName( HWND hWnd, LPTSTR lpClassName, int nMaxCount );

 이걸 찾을려고 온 MSDN을 다 뒤졌다는.. ㅡ_ㅡa...

 

이 글은 스프링노트에서 작성되었습니다.

+ Recent posts