C++/VC小技巧

【目  录】

1. 让程序只运行一次

2. 改变对话框的背景颜色

3. 让程序前端显示

4. “显示”链接LIB文件

5. 关闭其它应用程序

6. 系统托盘

7. 创建隐藏的对话框

8. 怎样使用高版本的函数和宏

9. 如何以动态的效果打开对话框

10.怎样以渐隐方式关闭对话框

11.动态改变光标

12.重写标题栏上的关闭按钮

13.重写F1帮助

14.如何从资源中释放文件

15.怎样截获ESC按键消息

16.如何给对话框加启动画面

17.如何在NT操作系统中关闭(重启)计算机

18.判断操作系统的版本


★ 让程序只运行一次

在源程序中的应用程序类的初始化函数【InitInstance()】中,添加以下代码:

CreateMutex( NULL, FALSE, "Application Mutex" );// 添加互斥量

if(GetLastError()==ERROR_ALREADY_EXISTS)

   return FALSE;

注意:要在函数的开始处添加代码。

返  回

 

     改变对话框的背景颜色

在对话框类的实现以前完成。同样,在应用程序类的初始化函数【InitInstance()】中,添加如下代码:

SetDialogBkColor(RGB(160,180,220),RGB(0,0,0));

// 注意第一个RGB是背景颜色,第二个RGB是前景颜色(文字)

// 也就是说,默认的第二个RGB(0,0,0),而且在VC 7.0中有问题

   注意:尽量在应用程序弹出对话框以前添加代码。

返  回

 

     让对话框始终显示在最前端

    只需要一个API函数【SetWindowPos()】就可以了,具体的函数参看下面:

BOOL SetWindowPos(
 HWND hWnd,             // handle to window
 HWND hWndInsertAfter,  // placement-order handle
 int X,                 // horizontal position
 int Y,                 // vertical position
 int cx,                // width
 int cy,                // height
 UINT uFlags            // window-positioning flags
);
下面给出一个例子,让对话框在最前端(显示)运行。

// 在对话框的初始化函数中的合适地方添加如下代码。

// TODO: Add extra initialization here

::SetWindowPos(this->m_hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);

return TRUE;  // return TRUE  unless you set the focus to a control

返  回

 

     “显示”链接LIB文件

如果程序中使用了动态链接库(DLL),而又非使用LoadLibrary()加载,那么在编译的时候需要在工程选项中的Link选项中手工添加所需的Lib文件。如果不想那么麻烦,也可以手工添加,即“显示”添加。添加的过程如下:在.CPP文件的首部,即在#include "headfile.h"后面加上#pragma comment(lib,"Library.lib")即可。好像在.h后面添加此句也可以的。

返  回

 

     关闭其它应用程序

想要关闭其它应用程序,只需要找到该应用程序的句柄,给其发关闭命令即可。具体实现参见下面代码:

void CloseOthers()

{

//定义一个应用程序句柄的指针

CWnd *pCwnd;

//用FindWindow函数找到想要关闭的应用程序的句柄的指针

pCwnd=FindWindow("lpszClassName","pszWindowName");

//如果返回成功

if( pCwnd )

pCwnd->SendMessage(SW_CLOSE);//给其发送关闭的消息

}

返  回

 

     系统托盘

如果将自己做的程序添加到系统托盘中,会给人一种你的程序很专业的感觉。其实要操作系统托盘很简单。首先,在对话框的头文件中添加自定义消息:

#define WM_TASKBAR WM_APP+1000

然后映射自定义消息,在如下地方添加代码:

BEGIN_MESSAGE_MAP(CMyDlg, CDialog)

// 在此处添加

ON_MESSAGE(WM_TASKBAR,OnTaskbar)

   //{{AFX_MSG_MAP(CAddiconDlg)

   ON_WM_SYSCOMMAND()

   ON_WM_PAINT()

   ON_WM_QUERYDRAGICON()

   ON_COMMAND(ID_MENUQUIT, OnMenuquit)

   //}}AFX_MSG_MAP

END_MESSAGE_MAP()

然后就是编写处理自定义消息的函数(右键单击弹出菜单):

LRESULT CMyDlg::OnTaskbar(WPARAM wParam, LPARAM lParam)

{

   if( lParam == WM_RBUTTONDOWN )

   {

       CMenu* menu;

       menu = new CMenu();

       menu->LoadMenu(IDR_MENU1);// 菜单是要提前做好的

       CMenu* pPopup=menu->GetSubMenu(0);

       ::SetMenuDefaultItem(pPopup->m_hMenu,0,TRUE); //设置粗体字

       CPoint Point;

       GetCursorPos(&Point);

   pPopup->TrackPopupMenu(TPM_LEFTALIGN,Point.x,Point.y,AfxGetMainWnd(),NULL);

   }

   return 0;

}

接下来是向系统托盘中加入图标,用函数来表示:

void CMyDlg::AddIcon()

{

   //图标句柄

   HICON hIcon;

   char lpszTip[] = "欢迎使用本程序!";

   HINSTANCE hInst = AfxFindResourceHandle(

MAKEINTRESOURCE(IDR_MAINFRAME),RT_GROUP_ICON);

              

   hIcon = (HICON)LoadImage(hInst,MAKEINTRESOURCE(IDR_MAINFRAME),

IMAGE_ICON,16,16,LR_DEFAULTCOLOR);

   //给NOTIFYICONDATA结构赋值

   NOTIFYICONDATA tnid;

   tnid.cbSize = sizeof(NOTIFYICONDATA);

   tnid.hWnd = m_hWnd;

   tnid.uID = IDR_MAINFRAME;

   tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;

   tnid.uCallbackMessage = WM_TASKBAR; //自定义消息

   tnid.hIcon = hIcon;

   if (lpszTip)

       lstrcpyn(tnid.szTip, lpszTip, sizeof(tnid.szTip));

   else

       tnid.szTip[0] = '/0';

   //调用Shell_NotifyIcon函数通过NIM_ADD向任务栏写图标

       Shell_NotifyIcon(NIM_ADD, &tnid);

       //释放图标资源

   if (hIcon)

       DestroyIcon(hIcon);

}

最后是编写删除托盘图标的函数:

void CMyDlg::DelIcon()

{

   //提供结构大小,窗口句柄和图标ID

   NOTIFYICONDATA tnid;

   tnid.cbSize = sizeof(NOTIFYICONDATA);

   tnid.hWnd = m_hWnd;

   tnid.uID = IDR_MAINFRAME;

   //用NIM_DELETE删除图标

   Shell_NotifyIcon(NIM_DELETE, &tnid);

}

返  回

 

     创建一个没有窗口的对话框

有时候,需要让一些程序运行的时候,不显示主窗口。感觉应该有两种办法,第一种是设置定时器,在程序运行的开始很短的一段时间内就调用ShowWindow()函数隐藏窗口。第二种方法是重写应用程序类的初始化函数,具体代码如下:

BOOL CMyApp::InitInstance()

{

   AfxEnableControlContainer();

 

   // Standard initialization

   // If you are not using these features and wish to reduce the size

   //  of your final executable, you should remove from the following

   //  the specific initialization routines you do not need.

 

#ifdef _AFXDLL

   Enable3dControls();         // Call this when using MFC in a shared DLL

#else

   Enable3dControlsStatic();   // Call this when linking to MFC statically

#endif

 

   CMyDlg *pdlg = new CMyDlg;

   m_pMainWnd = pdlg;

   pdlg->ShowWindow(SW_HIDE);

 

   // Since the dialog has been closed, return FALSE so that we exit the

   //  application, rather than start the application's message pump.

   return true;

}

注意比较和原来的代码有什么区别。以上代码在Debug模式下编译运行以后,有点问题,但在Release模式下一切都没有问题。不知道是为什么。

返  回

 

     怎样使用高版本的函数和宏

在开发应用程序的时候,我们可能会使用一些对版本要求比较高的函数和宏定义,所以需要做一些设置,否则编译器不会通过的,给出一个没有定义的消息。如何让编译器认识这些东西呢?就需要我们做点工作,如下:

// 在应用程序头文件的开始位置设置版本号

#undef WINVER

#define WINVER 0X500

返  回

 

     如何以动态的效果打开对话框

下面介绍如何让对话框以动态的效果弹出。

// 定义对话框类的成员变量

int m_nWidth,m_nHeight;

int m_nDx,m_nDy;

int m_nDx1,m_nDy1;

在对话框的初始化函数中添加如下代码:

   //获得窗口预设的大小

   CRect dlgRect;

   GetWindowRect(dlgRect);

   CRect desktopRect; 

//将窗口开始大小设为0

   GetDesktopWindow()->GetWindowRect(desktopRect);

   MoveWindow((desktopRect.Width() - dlgRect.Width()) / 2,

              (desktopRect.Height() - dlgRect.Height()) / 2,

              0, 0 );

   //初始化变化大小

   m_nWidth=dlgRect.Width();

   m_nHeight=dlgRect.Height();

   m_nDx=2;   m_nDy=4;

   m_nDx1=2;  m_nDy1=2;

   //设定定时器   

   SetTimer(1,10,NULL);

接下来就是编写定时器代码,参见下面的程序段:

   //获得此时窗口的实际大小

   CRect dlgRect;

   GetWindowRect(dlgRect);

   //获得桌面的大小

   CRect desktopRect;

   GetDesktopWindow()->GetWindowRect(desktopRect);

   //如果是窗口弹出过程,则逐渐增大窗口

   if(nIDEvent == 1)

   {

       MoveWindow(

                 (-m_nDx+desktopRect.Width() - dlgRect.Width()) / 2,

                 (-m_nDy+desktopRect.Height() - dlgRect.Height()) / 2,

                 +m_nDx+dlgRect.Width(), +m_nDy+dlgRect.Height() );

       //不要超过窗口预设的宽度

       if(dlgRect.Width() >=m_nWidth)

           m_nDx=0;

       //不要超过窗口预设的高度

       if(dlgRect.Height() >=m_nHeight)

           m_nDy=0;

       //停止变化,关闭定时器1

       if((dlgRect.Width() >=m_nWidth) && (dlgRect.Height() >=m_nHeight))

           KillTimer(1);

   }

   //停止变化,关闭定时器1

   if((dlgRect.Width() >=m_nWidth) && (dlgRect.Height() >=m_nHeight))

       KillTimer(1);

下面还以一种办法,就是使用Windows的高级函数,需要显示的定义版本号,方法参见上一部分(如何使用高版本的函数和宏定义)。具体使用函数的办法如下:

// 函数原型:

BOOL AnimateWindow(HWND hWnd,DWORD dwTime,DWORD dwFlags)  

/******************************************************************

函数功能:该函数能在显示与隐藏窗口时产生两种特殊类型的动画效果:滚动动画和滑动动画。

参数含义:

hWnd:  指定产生动画的窗口的句柄。

dwTime:指明动画持续的时间(以微秒计),完成一个动画的标准时间为200微秒。
dwFags:指定动画类型。这个参数可以是一个或多个下列标志的组合。标志描述:
AW_SLIDE:使用滑动类型。缺省则为滚动动画类型。当使用AW_CENTER标志时,这个标志就被忽略。
AW_ACTIVATE:激活窗口。在使用了AW_HIDE标志后不能使用这个标志。
AW_BLEND:实现淡出效果。只有当hWnd为顶层窗口的时候才可以使用此标志。
AW_HIDE:隐藏窗口,缺省则显示窗口。
AW_CENTER:若使用了AW_HIDE标志,则使窗口向内重叠,即收缩窗口;若未使用AW_HIDE标志,则使窗口向外扩展,即展开窗口。
AW_HOR_POSITIVE:自左向右显示窗口。该标志可以在滚动动画和滑动动画中使用。当使用AW_CENTER标志时,该标志将被忽略。
AW_VER_POSITIVE:自顶向下显示窗口。该标志可以在滚动动画和滑动动画中使用。当使用AW_CENTER标志时,该标志将被忽略。
AW_VER_NEGATIVE:自下向上显示窗口。该标志可以在滚动动画和滑动动画中使用。当使用AW_CENTER标志时,该标志将被忽略。
返  回

 

     怎样以渐隐方式关闭对话框

在应用程序的退出消息中添加如下代码:(详细说明见上面)

   // 以下函数需要5.0及其以上版本支持

   AnimateWindow(GetSafeHwnd(),1000,AW_HIDE|AW_BLEND);

返  回

 

     动态改变光标

以下代码解决当鼠标器指向某一个控件的时候动态改变光标。

// 重载对话框的下面这个虚函数

BOOL CMyDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)

{

   // TODO: Add your message handler code here and/or call default

   switch(pWnd->GetDlgCtrlID()) // 得到鼠标所在位置的控件的ID号

   {

   case IDOK:

       {

           SetCursor(AfxGetApp()->LoadCursor(IDC_CURSOR1));

           return TRUE;

       }

   default:

       {

           SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));

           return TRUE;

       }

   }

   return CDialog::OnSetCursor(pWnd, nHitTest, message);

}

返  回

 

     重写标题栏上的关闭按钮

有一些软件,当用户单击标题栏上的关闭按钮的时候,程序并没有结束运行,而是最小化了,下面的代码就是解决这个问题的。

// 重载下面的函数

void CRecorderDlg::OnSysCommand(UINT nID, LPARAM lParam)

{

   if (nID == SC_CLOSE)

       // 自定义的函数或代码

   else

       CDialog::OnSysCommand(nID, lParam);

}

返  回

 

     重写F1帮助

在应用程序中,如果按F1键的话,系统会默认的调用与应用程序同名的HLP文件,但我们往往使用CHM格式的帮助文件,如果响应F1呢?方法就是重载对话框的WinHelp()这个虚函数。代码如下:

void CMyDlg::WinHelp(DWORD dwData, UINT nCmd)
{

   // TODO: Add your specialized code here and/or call the base class

   if( GetKeyState (VK_F1) < 0 )
   {

       AfxMessageBox("you press F1");

       return;

   }

   CDialog::WinHelp(dwData, nCmd);

}
void CMyApp::WinHelp(DWORD dwData,UINT nCmd)
{
 CString str_path = _T("");
 GetModuleFileName(NULL,str_path.GetBufferLength(MAX_PATH+1),MAX_PATH);
 str_path.ReleaseBuffer();
 
 int i_pos = str_path.ReleaseFind('//');
 str_path = str_path.Left(i_pos);
        str_path = str_path + _T("//Help//Manual.chm");
 ShellExecute(NULL,"open",str_path,NULL,NULL);
 //CMyApp::WinHelp();
}

返  回

 

     如何从资源中释放文件

有些时候,我们的程序需要一些资源,通常都是放在和应用程序相同的文件夹下。

但是,这样做是比较不合适的。因为在移动的过程中很容易造成文件的丢失,所以,将自己的资源文件放在Resource中是比较合适的。但能够导入的资源类型比较少,有很多文件不支持,所以我们需要写些代码,从资源中释放这些文件,然后再供我们调用。当我们觉得这些文件比较重要的时候,还可以在这些文件使用完毕以后将它们删除。具体的方法见下面。

   举个例子,从资源中释放一个GIF文件,然后调用。

void CMyApp::LoadPictuer()

{

   CString szPic = "Welcome.gif";

   CFileFind find;

   if( !find.FindFile(szPic) )

       g_MakeResourceFromExe(szPic,"jig",IDR_JIG1);

   find.Close();

}

g_MakeResourceFromExe就是从资源中释放文件的函数,代码如下:

bool g_MakeResourceFromExe(CString szExPathName,CString szResName,int nResID)

{

   HRSRC hSrc = FindResource(NULL,MAKEINTRESOURCE(nResID),szResName);

   if(hSrc == NULL) return false;

  

   HGLOBAL hGlobal = LoadResource(NULL,hSrc);

   if(hGlobal == NULL) return false;

      

   LPVOID lp = LockResource(hGlobal);

   DWORD dwSize = SizeofResource(NULL,hSrc);

 

   CFile file;

   if(file.Open(szExPathName,Cfile::modeCreate|Cfile::modeWrite))

   {

       file.Write(lp,dwSize);

       file.Close();

   }

   FreeResource(hGlobal);

   return true;

}

g_MakeResourceFromExe函数可以直接拿来使用。但是释放出来的文件如何使用,那就要看自己怎样修改了。

返  回

     怎样截获ESC按键消息

用VC编写的基于对话框的应用程序,当用户按下ESC按键的时候,系统默认的处理是关闭对话框,如何编程实现截获ESC按键消息 ?这就需要我们重载一个虚函数来解决这个问题。参看下面的代码。

BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)

{

   // TODO: Add your specialized code here and/or call the base class

   //截获ESC和回车键,避免按下此键时关闭对话框

   if (pMsg->message == WM_KEYDOWN)

   {

     if(pMsg->wParam==VK_ESCAPE)

         return true;

     if(pMsg->wParam==VK_RETURN)

         return true;

   }

   return CDialog::PreTranslateMessage(pMsg);

}

   在以上代码中还处理了“回车”按键的消息,其实回车消息在VC中的处理并不是关闭对话框,而是处理的对话框的默认按钮的消息,但是VC默认的按钮是“确定”,所以一般的说,按下“Enter”就会执行IOK的函数,是对话框关闭的消息。想要改变这些,只需要将按钮的“默认按钮”项属性去掉就行了,或者在自己想执行的按钮属性中加上默认。

返  回

 

     如何给对话框加启动画面

前些时间看了一些文档,上面讲述了怎样给应用程序添加启动画面。文章讲述的是给非对话框的应用程序即SDI和MDI应用程序添加,用一个现有的控件(Splash Screen)就可以了。而要给对话框添加的话,就必须改写这个控件的代码,以适应对话框来使用。具体的代码已经有人改好了,我们只管那来用就可以了。在自己的工程中添加这个该好的类CsplashWnd,然后在应用程序类的初始化函数中添加几行代码就行了。如下:

//located in the local directory,or else full-path file name is needed

   CSplashWnd* pCsw = new CSplashWnd("welcome.jpg");

   pCsw->ShowSplash();

   Sleep(3000);//delay some time to observe the image displayed.

   pCsw->CloseSplash();

   delete pCsw;

   DeleteFile("welcome.gif");

   pCsw = NULL;

返  回

 

     如何在NT操作系统中关闭(重启)计算机

在编写程序的过程中需要让计算机重新启动,查阅MSDN得知需要用ExitWindowsEx函数。但是我试验了很多次,只有注销一个参数可以使用,感到很奇怪。我又反复的看了MSDN才得知,原来对于NT操作系统,不能随便的重启机器和关闭机器,若要进行以上操作,必须要具有相应的权限才可以,否则就不行,而Windows98就没有这个限制。我用的是WindowsXP,当然不让我关闭计算机了。其实写这段话的真正意义并不是要说怎么样在NT系统中关闭(重启)计算机,而是要说在NT操作系统中,如何给自己的应用程序(进程)增加特权。我查找了一些关于黑客和安全的技术文档,终于找到了解决的办法,参看下面的函数。

//为当前进程增加指定的特权

int AddPrivilege(const char *Name)

{

   HANDLE hToken;

   TOKEN_PRIVILEGES tp;

   LUID Luid;

 

   if (!OpenProcessToken(GetCurrentProcess(),

       TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,

       &hToken))

   {

       #ifdef _DEBUG

           printf("OpenProcessToken error./n");

       #endif

       return 1;

   }

 

   if (!LookupPrivilegevalue(NULL,Name,&Luid))

   {

       #ifdef _DEBUG

           printf("LookupPrivilegevalue error./n");

       #endif

       return 1;

   }

 

   tp.PrivilegeCount = 1;

   tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

   tp.Privileges[0].Luid = Luid;

 

   if (!AdjustTokenPrivileges(hToken,

       0,

       &tp,

       sizeof(TOKEN_PRIVILEGES),

       NULL,

       NULL))

   {

       #ifdef _DEBUG

           printf("AdjustTokenPrivileges error./n");

       #endif

       return 1;

   }

   return 0;

}

有了这个函数之后,我们就可以很方便的给我们的进程增加权限了,也就是说,可以给我们的应用程序增加关机的特权了,代码如下:

void OnShutdown()

{

   // TODO: Add your control notification handler code here

   AddPrivilege(SE_SHUTDOWN_NAME);

   ::ExitWindowsEx(EWX_SHUTDOWN,0);

}

返  回

 

     判断操作系统的版本

我们编程的时候,所要面对的操作系统,简单的说,大致可以分为两类,一类是NT操作系统,而另一类就是Windows95/98/Me操作系统,也就是说非NT操作系统。而两类操作系统对我们代码的编写就有不同的要求,因为两类操作系统的工作方式和原理是不一样的。比如说,上面提到的重新启动计算机的问题就是一个很明显的例子。所以我们需要判断程序运行的操作系统是不是NT系统,就可以了。下面这个函数,可以简单的判断当前的操作系统版本,具体参见代码和注释。

//判断系统版本

int GetOsVer(void)

{

   OSVERSIONINFO osvi;

   osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

   GetVersionEx (&osvi);

   //95,98 or Me

   if (osvi.dwPlatformId == VER_PLATform_WIN32_WINDOWS)

       return 1;

   //NT,2000,xp or 2003

   if (osvi.dwPlatformId == VER_PLATform_WIN32_NT)

       return 2;

   //Other

   return 0;

}

程序可以根据返回值执行不同的代码。

来源:
http://www.cnblogs.com/flyingleaf/archive/2004/06/01/12677.html
 
 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值