00 윈도우 프로그래밍 팁
원문 : http://kkamagui.springnote.com/pages/347952
들어가기 전에...
- 이 글은 kkamagui에 의해 작성된 글입니다.
- 마음껏 인용하시거나 사용하셔도 됩니다. 단 출처(http://kkamagui.tistory.com, http://kkamagui.springnote.com)는 밝혀 주십시오.
- 기타 사항은 kkakkunghehe at daum.net 이나 http://kkamagui.tistory.com으로 보내주시면 반영하겠습니다.
각종 윈도우 팁들 - 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 해서 아래의 코드를 넣어 주면 된다.
- if(pMsg->message == WM_SYSKEYDOWN && pMsg->wParam == VK_F4)
{
return TRUE;
}
익스플로러가 죽어도 트레이아이콘에 계속 상주시키기
- // 메시지 등록 과정
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(가변 인자)
- // 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 로 얻으면 된다.
윈도우 공유 폴더 로그인 시 이상한 계정으로 로그인 되는 경우
관리도구->사용자계정->좌측 상단의 네트워크 연결관리 에서 서버와 계정을 추가한다.
툴팁 생성하기
툴팁 생성 코드
- m_clToolTip.Create( this, WS_VISIBLE | WS_BORDER );
m_clToolTip.AddTool( this, "" );
m_clToolTip.SetDelayTime( 100 );
m_clToolTip.Activate( TRUE );
툴팁 표시를 위한 메시지 릴레이 코드
- /**
Enter와 Esc로 인한 종료를 막는다.
*/
BOOL CSubPartition::PreTranslateMessage(MSG* pMsg)
{
if( pMsg->message == WM_KEYDOWN )
{
if( ( pMsg->wParam == VK_ESCAPE ) ||
( pMsg->wParam == VK_RETURN ) )
{
return TRUE;
}
} - // ToolTip 표시를 위해 메시지 릴레이 설정
m_clToolTip.RelayEvent(pMsg);
return CDialog::PreTranslateMessage(pMsg);
}
Shell Execute로 프로그램 실행하기
- 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로 웹 연결하기
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의 아래부분을 막거나 변경한다.
- ON_COMMAND(ID_HELP, CApp::OnHelp)
DLL의 함수 Export시 정해진 이름으로 Export 하기
DLL의 함수를 그냥 Export 하면 함수 이름 그대로 Export 되지 않고 기타 정보가 더 붙는다. extern을 사용하면 어느정도 해결되지만 확실한 해결책은 def 파일을 이용하는 것이다. 아래와 같이 쓰면된다.
- LIBRARY MyDll
EXPORTS
Function1=Function1
Function2=Funciton2 - Data1 DATA <== 데이터를 외부로 Export 할때
- Function3 @1 <== 서수를 같이 Export 할때
- Function4 @2 NONAME <== 서수로만 Export 할때, 함수 이름 포함 X
- Function5 PRIVATE <== lib 파일에 Function5에 대한 내용 제외, DLL에는 있음
파일(File) 및 라인(Line) 관련 매크로(Macro)
- __FILE__ : 해당 파일 이름으로 대체
- __LINE__ : 해당 라인 번호로 대체
- printf( "%d %d", __FILE__, __LINE__ );
printf 직접 구현하기
C/C++의 Calling Convention을 보면 Stack에 파라메터를 넘긴다. 이것을 이용하여 Variable Argument List를 찾아서 넣는 방식이다.
- /**
임의로 만든 printf 함수
printf 함수의 간략버전
*/
void kPrintf( char* pcFormat, ... )
{
DWORD* pdwArg;
char vcBuffer[ 1024 ];
int iBufferIndex;
int iFormatIndex;
char* pcString;
int iLength; - // 2번째 Argument를 pdwArg가 가리키고 있다.
pdwArg = ( DWORD* ) &pcFormat + 1;
iBufferIndex = 0;
iFormatIndex = 0; - // 문자열 끝까지 한다.
while( pcFormat[ iFormatIndex ] != '\0' )
{
if( pcFormat[ iFormatIndex ] != '%' )
{
vcBuffer[ iBufferIndex ] = pcFormat[ iFormatIndex ];
iFormatIndex++;
iBufferIndex++;
continue;
} - iFormatIndex++;
switch( pcFormat[ iFormatIndex ] )
{
// 16진수 출력
case 'X':
case 'x':
// 10진수 출력
case 'd':
kDToA( vcBuffer + iBufferIndex, *pdwArg );
iBufferIndex += 8;
iFormatIndex++;
pdwArg++;
break; - // 문자열 출력
case 's':
pcString = ( char* )( *pdwArg );
iLength = strlen( pcString ); - 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) 내용 보기
아래와 같이 입력하면 에러코드와 내용을 볼 수 있다.
- @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
- 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
- void CMainFrame::DeleteSysTray()
{
NOTIFYICONDATA data;
data.cbSize = sizeof( NOTIFYICONDATA );
data.hWnd = m_hWnd;
data.uID = IDR_MAINFRAME;
Shell_NotifyIcon( NIM_DELETE , &data );
}
3.메시지 처리
- LONG CMainFrame::OnSystrayClicked( WPARAM wParam , LPARAM lParam )
{
CYesNoDlg dlg; - 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.태스크바가 다시 생성되었을 때 재등록
- 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"로 바꿔줘야 나온다.
- 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; - }
- BOOL CHidDlgDlg::ShowWindowEx(int nCmdShow)
{
m_bShowFlag = (nCmdShow == SW_SHOW);
return (GetSafeHwnd()) ? ShowWindow(nCmdShow) : TRUE;
} - 출처 : Tong - luster님의 Tip통
윈도우 핸들(Window Handle, hwnd)로 클래스 이름(Class Name) 얻기
- int GetClassName( HWND hWnd, LPTSTR lpClassName, int nMaxCount );
이걸 찾을려고 온 MSDN을 다 뒤졌다는.. ㅡ_ㅡa...