VC小技巧
2008-05-26 09:26
197 查看
1、禁止同一应用程序同时运行
有时候为了避免不必要的错误,应防止同一应用程序被打开两个实例
以下一个函数可以达到此项目的,挺有用的!
BOOL C××App::AlreadyRunning()
{
BOOL bFound = FALSE;
// Try to create a mutex with the app's name
HANDLE hMutexOneInstance = ::CreateMutex(NULL,TRUE,_T(AfxGetAppName()));
// Already there...means that we are already running an instance
if(::GetLastError() == ERROR_ALREADY_EXISTS)
bFound = TRUE;
// Release the mutex
if(hMutexOneInstance)
::ReleaseMutex(hMutexOneInstance);
return(bFound);
}
只要在
BOOL C**App::InitInstance()
{
// Is it already running?
if(AlreadyRunning())
{
// Yep...get out now
AfxMessageBox(IDS_ALREADY_RUNNING,MB_ICONWARNING);
return(FALSE);
}
。。。。。
}
2、托盘区图标操作
经常能够看到软件运行后在托盘产生图标 ,其实也就是对结构 NOTIFYICONDATA 的设置再调用Shell_NotifyIcon就能完成
NOTIFYICONDATA notifycd;
notifycd.cbSize=sizeof(NOTIFYICONDATA);
notifycd.hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);//图标资源
notifycd.hWnd=m_hWnd;
notifycd.uID=IDR_MAINFRAME;
notifycd.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;
lstrcpy( notifycd.szTip, _T( "" ) ); //默认的tooltip上的文字
notifycd.uCallbackMessage = WM_SHELLNOTIFY; //一旦在任务栏上产生图标,就回触发一定的消息
Shell_NotifyIcon(NIM_ADD,¬ifycd);
任务栏图标上的消息处理映射
ON_MESSAGE( WM_SHELLNOTIFY, OnShellNotify)
显示,删除,修改函数详细操作
//在托盘区显示图标
BOOL AddNotifyIcon(UINT Icon,LPCTSTR sztip, UINT ID)
{
HICON hIcon;
hIcon=AfxGetApp()->LoadIcon(Icon);
NOTIFYICONDATA idata;
idata.cbSize=sizeof(NOTIFYICONDATA);
idata.hIcon=hIcon;
CWnd *pWnd=AfxGetMainWnd();
idata.hWnd=GetSafeHwnd();
strcpy(idata.szTip,sztip);
idata.uCallbackMessage=WM_SHELLNOTIFY;
idata.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;
idata.uID=ID;
return Shell_NotifyIcon(NIM_ADD,&idata);
}
//在托盘区删除图标
BOOL DeleteNotifyIcon(UINT Icon,LPCTSTR sztip, UINT ID)
{
HICON hIcon;
hIcon=AfxGetApp()->LoadIcon(Icon);
NOTIFYICONDATA idata;
idata.cbSize=sizeof(NOTIFYICONDATA);
idata.hIcon=hIcon;
CWnd *pWnd=AfxGetMainWnd();
idata.hWnd=GetSafeHwnd();
strcpy(idata.szTip,sztip);
idata.uCallbackMessage=WM_SHELLNOTIFY;
idata.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;
idata.uID=ID;
return Shell_NotifyIcon(NIM_DELETE,&idata);
}
//在托盘区修改图标
BOOL ModifyNotifyIcon(UINT Icon,LPCTSTR sztip, UINT ID)
{
HICON hIcon;
hIcon=AfxGetApp()->LoadIcon(Icon);
NOTIFYICONDATA idata;
idata.cbSize=sizeof(NOTIFYICONDATA);
idata.hIcon=hIcon;
CWnd *pWnd=AfxGetMainWnd();
idata.hWnd=GetSafeHwnd();
strcpy(idata.szTip,sztip);
idata.uCallbackMessage=WM_SHELLNOTIFY;
idata.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;
idata.uID=ID;
return Shell_NotifyIcon(NIM_MODIFY,&idata);
}
3、右键菜单的使用
平时经常会看到一些软件把一些常用的功能集成在右键菜单中,这样能够是菜单灵活,易用!以下函数完成了弹出式菜单的创建,只要在右键点击的消息响应中调用就能完成想要的右键菜单的功能!
void PopupMenu()
{
CPoint point;
GetCursorPos( & point );
CMenu menuPopup;
menuPopup.CreatePopupMenu();
menuPopup.AppendMenu( MF_STRING, ID_MENUITEM_ABOUT, _T( "about" ) );
menuPopup.AppendMenu( MF_SEPARATOR );
menuPopup.AppendMenu( MF_STRING, ID_MENUITEM_SHOW, _T( "open" ) );
menuPopup.AppendMenu( MF_SEPARATOR );
menuPopup.AppendMenu( MF_STRING, ID_MENUITEM_EXIT, _T( "exit" ) );
menuPopup.AppendMenu( MF_SEPARATOR );
menuPopup.AppendMenu( MF_STRING, ID_MENUITEM_CANCEL, _T( "cancel" ) );
int nCmd = ( int ) menuPopup.TrackPopupMenu( /
TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, /
point.x, point.y, /
AfxGetMainWnd() );
switch( nCmd )
{
case ID_MENUITEM_EXIT:
。。。。。。。
break;
case ID_MENUITEM_SHOW:
。。。。。。。。。。。
break;
case ID_MENUITEM_ABOUT:
default:
break;
}
}
4、消息循环重载
当应用程序进行复杂计算或占用很多系统资源的操作时,用户点击程序界面按钮时无法响应,有两种解决方法:计算线程,消息循环重载技术,即在应用程序中处理Windows消息循环。这样既可以在主线程中进行复杂计算以满足实时计算要求,又能即使响应用户输入,随时中止计算!举例如下:
while(!m_bStop && iStep <= 500) {
iStep++;
m_pgProgress.StepIt();
Sleep(20);
DoEvents(); // 二次消息循环函数
}
void DoEvents()
{
MSG msg;
if (::PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { //从Windows消息队列中取出消息
if (msg.message== WM_QUIT)//如果消息为退出,发送退出消息
{
::PostQuitMessage(-1);
}
if(!AfxGetApp()->PreTranslateMessage(&msg))//如果无法预处理消息
{
::TranslateMessage(&msg);//转换消息
::DispatchMessage(&msg);//发送消息
}
}
AfxGetApp()->OnIdle(0);AfxGetApp()->OnIdle(1);//消息队列为空时闲置一段时间
}
5、运行后自删除程序
当一个可执行程序exe在执行过程中,程序文件无法删除,这是因为系统将每个正在运行的程序对应的硬盘文件映射到内存,即虚拟内存,要实现自删除,关键一点在程序退出前将程序从内存映射中解放出来,然后
再调用文件操作函数删除程序文件!
typedef int (WINAPI *PFClose)(LPVOID);
OSVERSIONINFO os_info;
os_info.dwOSVersionInfoSize=sizeof(os_info);
LPVOID pBuffer=NULL;
PFClose pClose,pDelete;
char fn[4096];
HINSTANCE hins=GetModuleHandle(NULL); // 得到本程序句柄
GetModuleFileName(NULL,fn,4096); // 得到本程序名称
if(!GetVersionEx(&os_info)) // 得到当前Windows系统版本
return FALSE;
switch(os_info.dwPlatformId)
{
case VER_PLATFORM_WIN32_NT: // 当前系统为WinNT平台系统
__try
{
while(CloseHandle((HANDLE)4));
}
__except(1)
{ }
CloseHandle((HANDLE)4);
pClose=PFClose(UnmapViewOfFile);
break;
case VER_PLATFORM_WIN32_WINDOWS: // 当前系统为Win9X平台系统
pClose=PFClose(FreeLibrary);
break;
default:
return FALSE;
}
pDelete=PFClose(DeleteFile);
pBuffer=VirtualAlloc(NULL,4096,MEM_COMMIT,PAGE_EXECUTE_READWRITE);
_asm
{
call _delete_end
}
_asm // 尝试关闭并删除程序
{
_test_close:
push hins
call [pClose] // 关闭程序
or eax,eax
jz _test_close
lea eax,fn
948a
push eax
call [pDelete] // 删除程序
or eax,eax
jz _Exit_Process
call eax
_Exit_Process: // 退出进程
push 0
push MEM_RELEASE
push 0
push pBuffer
push ExitProcess // 退出进程
push VirtualFree
ret
}
_delete_end: // 删除准备工作
_asm
{
pop ebx
push 128
push ebx
push [pBuffer]
call memcpy
jmp pBuffer
}