学习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);

}

 

 

*      如何从资源中释放文件

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

但是,这样做是比较不合适的。因为在移动的过程中很容易造成文件的丢失,所以,将自己的资源文件放在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;

}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值