VC小技巧

来源:互联网 发布:触摸屏编程视频教程 编辑:程序博客网 时间:2024/04/30 11:48

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,&notifycd);
任务栏图标上的消息处理映射
    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
         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
    }