VC 为程序创建快捷方式的详细讲解

有时候,为了方便用户使用我们编写的程序,需要在桌面,快速启动或程序组中创建程序的快捷方式。

下面就介绍在VC下如何为程序创建快捷方式。

一.得到桌面,快速启动或程序组的路径

这里介绍二个win32 API函数来完成这个任务。

 

第一个函数用来获得系统特殊路径

HRESULT SHGetSpecialFolderLocation(
    HWND hwndOwner,  int nFolder, PIDLIST_ABSOLUTE *ppidl
);

第一个参数表示所有者窗口句柄,一般传入NULL就可以了;

第二个参数要示是一个整数id,决定哪个目录是待查找目录,它的取值可能是:

  • CSIDL_BITBUCKET                    回收站
  • CSIDL_CONTROLS                           控制面板
  • CSIDL_DESKTOP                              Windows桌面desktop;
  • CSIDL_DESKTOPDIRECTORY       desktop的目录;
  • CSIDL_DRIVES                                 我的电脑
  • CSIDL_FONTS                                   字体目录
  • CSIDL_NETHOOD                            网上邻居
  • CSIDL_NETWORK                           网上邻居virtual folder
  • CSIDL_PERSONAL                          我的文档
  • CSIDL_PRINTERS                            打印机
  • CSIDL_PROGRAMS                         程序组
  • CSIDL_RECENT                               最近打开文档
  • CSIDL_SENDTO                               发送到菜单项
  • CSIDL_STARTMENU                       快速启动菜单
  • CSIDL_STARTUP                             启动目录
  • CSIDL_TEMPLATES                        临时文档

第三个参数表示一个条目标识符列表指针,可以传入一个LPITEMIDLIST类型变量,再从这个变量中得到表示路径的字符串。使用完后,要用void CoTaskMemFree(void * pv)来释放资源。

 

第二个函数用于将一个条目标识符列表转换为一个文件系统路径

BOOL SHGetPathFromIDList( 
    PCIDLIST_ABSOLUTE pidl,  LPTSTR pszPath
);

第一个参数 pidl就是用第一个函数所得到的条目标识符列表指针;

第二个参数pszPath返回表示路径的字符串;

 

这二个函数的头文件均为<shlobj.h>并要引入shell32.lib

 

下面给出了一个程序,用来列举你电脑上一些系统特殊路径:

#include <stdio.h>
#include <windows.h>
#include <shlobj.h>
#pragma comment(lib, "shell32.lib")

int main() {
   const int ENDNUMBER = -1;//哨兵,在遍历数组时遇到此数表示已经到达了数组的最后。

   //设置这个后,你可以在nFolders数组中任意添加删除数据而不用在遍历数组时考虑其中有多少个数据。

   CoInitialize(NULL);
       int nFolders[] = {
           CSIDL_BITBUCKET, CSIDL_CONTROLS, CSIDL_DESKTOP, CSIDL_DESKTOPDIRECTORY,
           CSIDL_DRIVES, CSIDL_FONTS, CSIDL_NETHOOD, CSIDL_NETWORK, CSIDL_PERSONAL,
           CSIDL_PRINTERS, CSIDL_PROGRAMS, CSIDL_RECENT, CSIDL_SENDTO, CSIDL_STARTMENU,
           CSIDL_STARTUP, CSIDL_TEMPLATES, ENDNUMBER
       };

       HRESULT       hr;
       LPITEMIDLIST  ppidl;
       char          szPath[MAX_PATH];

       int i = 0; 
       while (nFolders[i] != ENDNUMBER) {
           hr = SHGetSpecialFolderLocation(NULL, nFolders[i], &ppidl);

           if (hr != S_OK) {
              printf("SHGetSpecialFolderLocation Error\n");
           }
           else {
               if (SHGetPathFromIDList(ppidl, szPath))
                   printf("%s\n", szPath);
               else
                   printf("SHGetPathFromIDList Error\n");
                   CoTaskMemFree(ppidl);
           }
           i++;
       }
       CoUninitialize();
       return 0;
}

 

由于系统的差异,有时会输出“SHGetPathFromIDList Error”,在我电脑上就输出了5次。有了这个例子,相信不难写出得到桌面桌面(CSIDL_DESKTOP),快速启动CSIDL_APPDATA),程序组(CSIDL_PROGRAMS)的路径函数。

不过要稍稍注意下快捷启动,要再加上"\\Microsoft\\Internet Explorer\\Quick Launch"

二.创建快捷方式文件

完成第一步的任务后接下来的问题是如何创建快捷方式文件即.lnk文件。首先要了解快捷方式文件要设置什么,然后了了解怎样设置。

2.1 快捷方式文件有哪些要设置的内容

下面给出了Spy++Kmplayer Plus二个程序的快捷方式。

 

快捷方式必须设置目标,起始位置,快捷键,备注都可以选择性的设置,运行方式一般取默认值----常规窗口。

 

 

2.2如何设置快捷方式文件的内容

这要用到二个COM接口IShellLinkIPersistFile。由于篇幅问题,这里只讲解二个接口的部分函数。

IShellLink的部分函数

  • HRESULT SetPath(LPCTSTR pszFile);                          设置目标
  • HRESULT SetWorkingDirectory(LPCTSTR pszDir);     设置起始位置
  • HRESULT SetHotkey(WORD wHotkey);                       设置快捷键
  • HRESULT SetShowCmd(int iShowCmd);                       设置运行方式

 

有三种选择:

  • SW_SHOWNORMAL                                                         常规窗口
  • SW_SHOWMAXIMIZED                                                         最大化
  • SW_SHOWMINNOACTIVE                                              最小化
  • HRESULT SetDescription(LPCTSTR pszName);            设置备注

要特别说下SetHotkey()中的参数WORD wHotkeyMSDN上对其的解释为:The address of the hot key. The virtual key code is in the low-order byte, and the modifier flags are in the high-order byte. The modifier flags can be a combination of the following values.

  • HOTKEYF_ALT                                                    ALT key
  • HOTKEYF_CONTROL                                             CTRL key
  • HOTKEYF_EXT                                                    Extended key
  • HOTKEYF_SHIFT                                                 SHIFT key

意思就是对这个WORD值,低位上是virtual key code,高位上可以是ALT,CTRL等组合键。可以用MAKEWORD(low, high)来生成一个WORD,如Ctrl+F12可以用MAKEWORD(VK_F12, HOTKEYF_CONTROL)表示。

 

IPersistFile的部分函数:

HRESULT Save(          保存快捷方式
  LPCOLESTR pszFileName, BOOL fRemember
);

第一个参数是要保存文件的文件名,要求是绝对路径。

第二个参数涉及COM的持续性问题(注1),一般传入TRUE即可。

 

要创建COM对象可以用CoCreateInstance()函数(见注2)和QueryInterface()函数(见注3)。下面给出了创建的代码:

IShellLink     *pLink;     // IShellLink对象指针
IPersistFile    *ppf;       // IPersisFil对象指针

 

创建IShellLink实例:

CoCreateInstance(CLSID_ShellLink,NULL,CLSCTX_INPROC_SERVER,IID_IShellLink,(void**)&pLink);

IShellLink对象中获取IPersistFile接口

pLink->QueryInterface(IID_IPersistFile, (void**)&ppf);

创建之后就可以对pLink设置目标,快捷键,备注等,设置完后再用ppf创建快捷方式文件就可以了。当然最后要记得释放资源,pLink->Release(); ppf->Release()

 

三.已封装好的函数代码

下面给出封装好的函数代码,可以在程序中直接使用(在XP+VC6.0下测试过)。

// 得到当前桌面路径
BOOL GetDesktopPath(char *pszDesktopPath) {
    LPITEMIDLIST  ppidl = NULL;
    
    if (SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &ppidl) == S_OK) {
        BOOLflag =   SHGetPathFromIDList(ppidl, pszDesktopPath);
        CoTaskMemFree(ppidl);
        return flag;
     }
     return FALSE;
}    

// 得到快速启动栏的路径
BOOL GetIEQuickLaunchPath(char *pszIEQueickLaunchPath) {    
     LPITEMIDLIST  ppidl;                   

     if (SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &ppidl) == S_OK) {
          BOOLflag =   SHGetPathFromIDList(ppidl, pszIEQueickLaunchPath);
          strcat(pszIEQueickLaunchPath, "\\Microsoft\\Internet Explorer\\Quick Launch");
          CoTaskMemFree(ppidl);
          return flag;
     }
     return FALSE;
}

//得到开始->程序组的路径
BOOL GetProgramsPath(char *pszProgramsPath) {
    LPITEMIDLIST  ppidl;
    if (SHGetSpecialFolderLocation(NULL, CSIDL_PROGRAMS, &ppidl) == S_OK) {
       BOOLflag = SHGetPathFromIDList(ppidl, pszProgramsPath);
       CoTaskMemFree(ppidl);
       return flag;
    }

    return FALSE;
}

/*
函数功能:对指定文件在指定的目录下创建其快捷方式
函数参数:
    lpszFileName    指定文件,为NULL表示当前进程的EXE文件。
    lpszLnkFileDir  指定目录,不能为NULL。
  lpszLnkFileName 快捷方式名称,为NULL表示EXE文件名。
  wHotkey         为0表示不设置快捷键
  pszDescription  备注
  iShowCmd        运行方式,默认为常规窗口
*/

BOOL CreateFileShortcut(LPCSTRlpszFileName, LPCSTRlpszLnkFileDir, LPCSTRlpszLnkFileName, LPCSTRlpszWorkDir, WORDwHotkey, LPCTSTRlpszDescription, int iShowCmd = SW_SHOWNORMAL) {
       if (lpszLnkFileDir == NULL)
          return FALSE;

       HRESULThr;
       IShellLink     *pLink;  //IShellLink对象指针
       IPersistFile   *ppf; //IPersisFil对象指针

       //创建IShellLink对象
       hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pLink);
       if (FAILED(hr))
           return FALSE;

       //从IShellLink对象中获取IPersistFile接口
       hr = pLink->QueryInterface(IID_IPersistFile, (void**)&ppf);
       if (FAILED(hr)) {
              pLink->Release();
              return FALSE;
       }

       //目标
       if (lpszFileName == NULL)
          pLink->SetPath(_pgmptr);
       else
          pLink->SetPath(lpszFileName);

       //工作目录
       if (lpszWorkDir != NULL)
          pLink->SetPath(lpszWorkDir);
//快捷键 if (wHotkey != 0)
      pLink
->SetHotkey(wHotkey);
//备注 if (lpszDescription != NULL) pLink->SetDescription(lpszDescription); //显示方式 pLink->SetShowCmd(iShowCmd); //快捷方式的路径 + 名称 char szBuffer[MAX_PATH]; if (lpszLnkFileName != NULL) //指定了快捷方式的名称 sprintf(szBuffer, "%s\\%s", lpszLnkFileDir, lpszLnkFileName); else { //没有指定名称,就从取指定文件的文件名作为快捷方式名称。 char *pstr; if (lpszFileName != NULL) pstr = strrchr(lpszFileName, '\\'); else pstr = strrchr(_pgmptr, '\\'); if (pstr == NULL) { ppf->Release(); pLink->Release(); return FALSE; } // 注意后缀名要从.exe改为.lnk sprintf(szBuffer, "%s\\%s", lpszLnkFileDir, pstr); int nLen = strlen(szBuffer); szBuffer[nLen - 3] = 'l'; szBuffer[nLen - 2] = 'n'; szBuffer[nLen - 1] = 'k'; } // 保存快捷方式到指定目录下 WCHAR wsz[MAX_PATH];      // 定义Unicode字符串 MultiByteToWideChar(CP_ACP, 0, szBuffer, -1, wsz, MAX_PATH); hr = ppf->Save(wsz, TRUE); ppf->Release(); pLink->Release(); return SUCCEEDED(hr); }

 

调用如下例:

int main() {
   char  szPath[MAX_PATH];
   CoInitialize(NULL);
   GetDesktopPath(szPath);

   if (CreateFileShortcut(NULL, szPath, NULL, NULL, MAKEWORD(VK_F12, HOTKEYF_CONTROL), "That is a test"))
       printf("创建成功\n");

   CoUninitialize();
       return 0;
}

 

头文件及引用库:

#include <stdio.h>
#include <windows.h>
#include <shlobj.h>
#pragma comment(lib, "shell32.lib")

 

效果如图:

 

posted @ 2020-03-12 20:48  seeyoumeet  阅读(474)  评论(0编辑  收藏  举报