热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

用IShellLink解析快捷方式(ShortCut)

前几天要写一个解析快捷方式的程序,发现MSDN上有篇文章,转了过来本想翻译一下的,想想英语比较弱,作罢。UsingShell

前几天要写一个解析快捷方式的程序,发现MSDN上有篇文章,转了过来 

本想翻译一下的,想想英语比较弱,作罢。

Using Shell Links in Windows 95

Nancy Winnick Cluts
Microsoft Developer Network Technology Group

October 1994
Revised: June 1995 (Added "Using MFC" section; added information about per-user profiles; changed second parameter of IPersistFile::Save method from STGM_READ to TRUE)
Revised: July 1996 (Updated section covering creation of shortcuts to support per-user profiles)
Revised: October 1996 (Updated the sample application and its build information)

 

Abstract

The next version of the Microsoft® Windows® operating system, Windows 95, has a new shell and a way to create shell links (also known as shortcuts) to items or objects in the shell. Shell links provide an easy method for users to access and manipulate objects regardless of the location and name of the object. For example, if a shell link is created to a text file, and if the original text file is subsequently renamed, the original shell link is updated by the shell without needing user intervention (that is, the user does not have to recreate the shell link). Creating a shell link from the standpoint of the end user is as easy as clicking the mouse; however, creating such a link from the standpoint of an application takes a bit more work. This is the first of two articles covering shell links. This article contains background information about shell links and discusses the method used to create and resolve them using the built-in menus from the shell and programmatically. The second article, "The IShellLink Interface," covers some of the underpinnings the system has put in place to implement shell links: the IShellLink interface and how the shell preserves links.

What Are Shell Links?

Shell links (also known as shortcuts) are a convenient way to reference objects within the shell name space (the hierarchical structure of objects in the Microsoft® Windows® 95 shell) without having to keep track of the name and the location of the original object. Shell links are referred to as shortcuts in the context menu (the menu that pops up when you click the object with the right mouse button) of shell objects; however, they are implemented internally via the IShellLink interface. As a result, when I refer to shell links I am also referring to shortcuts: They are the same thing. There are many objects to which you can create shell links. Some examples of objects to which you can create shell links within the shell name space are:

  • Files
  • Directories
  • Control Panel
  • Printers
  • Mail
  • Your application

When you install the beta release of Windows 95, a shell link is automatically created and placed on the desktop for the README file that comes with the system (as shown in Figure 1). You know you are looking at a shell link by the small arrow in the lower-left corner of the icon. Clicking this icon once brings up WordPad with the Windows 95 Beta Release Notes initially loaded.

 

Figure 1. A shell link

Some Benefits of Shell Links

One benefit of shell links is the inherent transparency to the user of the original object's name and location. For example, if you were to create a shell link for a file and were to place that shell link on the desktop, then when the user clicked that file, the file would be activated (the default action would occur for that file). So, if the file were a Microsoft Word document, clicking the shell link would execute Word with the file specified as the current working document. When you create a shell link to one of the objects that resides in the shell name space, you are creating a reference to that item within the context of the shell name space. Although I suspect that the most common shell objects for which end users and application developers can create shell links are files and folders, you can also create shell links to printers or to Control Panel. If you create a shell link to a printer and then change the network location for the printer, the link will still work (you will still be able to print to that printer using the link) and the user would never know that the server has changed: The location is transparent to the user.

Shell links are also useful for installation applications. The Windows 95 Setup program uses shell links itself when it places the shell link to its README on the desktop. Another place to use shell links is for a "last opened document." For example, let's say that you have a multiple-document interface (MDI) application and you want to keep track of the last document that was opened for the user. One way to do this is to create a shell link for the user, who can subsequently click that shell link whenever she wants to run your application again in the context of that document.

How an End User Creates a Shell Link

The shell has a built-in mechanism for creating shell links via the right-click context menu it provides for objects within the shell name space. End users may use this mechanism to create shell links of their own. To create a shell link and put it on the desktop, for instance, the user performs the following steps

  1. Find the object (folder, printer, program, computer) that is the target of the shell link.
  2. Click the object with the right mouse button and click Create Shortcut on the context menu (or click Create Shortcut on the File menu in Explorer as shown in Figure 2). This creates the shell link.

    Figure 2. Create Shortcut menu item

  3. Drag the shell link to the desktop and drop it to place the shell link on the desktop.

Some Background About IShellLink

Okay, so the shell has this functionality built in. But what if you are writing your own application and want to be able to programmatically create a shell link for the end user? Can this be done?

Of course it can. Besides, would I even ask the question if the answer were no?

Because shell links are implemented via the IShellLink interface, it is helpful to understand some of the basic concepts of OLE when programming a shell link; however, it is by no means mandatory to be an OLE guru to do so. If it were, I never would have been able to create a link. The most important area you should read up on to understand and use shell links is the Component Object Model. Reading the first four chapters of Inside OLE by Kraig Brockschmidt (MSDN Library, Books) should give you sufficient background.

For those of you, though, who aren't going to read those first four chapters (I know who you are, and you should be ashamed of yourselves!), I will give you a very brief overview of the Component Object Model.

Component Object Model

The Component Object Model is a specification that describes the process of communicating through interfaces, acquiring access to interfaces through the QueryInterface method, determining pointer lifetime through reference counting, and reusing objects by extending them.

An object is an item in the system that exposes interfaces (groups of related functions) to manipulate the data or properties of the object. It is created directly or indirectly by calling the CoCreateInstance function, which creates a new instance of the object and returns a pointer to the interface for the object. When two objects within the system want to communicate with one another, they call functions within the object's interface via a pointer to the interface. This interface pointer is the one that was returned by the call to CoCreateInstance. A typical time when two objects may want to communicate with each other is during a drag-and-drop operation. During this operation, the object to be dropped on the other object calls into the other object's interface to request acceptance of the drop.

All interfaces used in the Component Object Model, including the one we will use to manipulate shell links (IShellLink), support the base interface, IUnknown. The IUnknown interface supports three methods (or functions):

  • QueryInterface: Determines whether a specific interface is supported for the object.
  • AddRef: Increments the reference count on an interface.
  • Release: Decrements the reference count on an interface. Once an interface's reference count goes to zero, the object deletes itself and the pointer to that interface is no longer valid. If the reference count on all of an object's interfaces is zero, the object can be freed because there are no longer any pointers to the object.

The Tools I Used to Create a Shell Link

The sample that accompanies this technical article, SHORTCUT.EXE, is a Microsoft Foundation Class Library (MFC) application that was created with Microsoft Visual C++® version 4.2  and the Win32 SDK.

Initialization

There are some OLE basics that you need to do to create and resolve your shell links. The first thing that your application must do upon startup is to initialize the component object library with a call to CoInitialize or OleInitialize. I put this call in my sample code, SHORTCUT.CPP, in my InitInstance handler before I called anything else. Each call to CoInitialize needs to be balanced with a call to CoUninitialize. CoUninitialize should be called when an application shuts down. It ensures that the application won't quit until it has received all of its pending messages. I put my call to CoUninitialize in my ExitInstance handler.

Creating a Shell Link to a File

To demonstrate how to create a shell link, I created a very simple MFC application that allows the user to choose a file from the current directory to which a shell link is to be created. For example, if you want to create a shell link to a text file named README, you would choose README.TXT from the list. When the user chooses the Create Shortcut menu item, a dialog box displays a list of the files in the current directory (Figure 3).

Figure 3. Dialog box for creating a shortcut in the SHORTCUT sample

The following code makes use of the handy-dandy DlgDirList function to fill my list box in the dialog box.

BOOL CreateShortCut::OnInitDialog()
{DWORD cchCurDir;char szCurDir[MAX_PATH];CDialog::OnInitDialog();// Initialize the list box by filling it with files from// the current directory.GetCurrentDirectory(cchCurDir, szCurDir);DlgDirList(szCurDir, ID_LBOX, 0, DDL_READWRITE);return TRUE;
}

After the user chooses a file from the list and clicks the OK button, a check is made to determine whether the link is targeted to the desktop or to the current directory. The user indicates whether to target the shell link to the desktop by checking the "Place shortcut on desktop" option in the dialog box. If it is targeted to the desktop, its default location will be in a subdirectory (called DESKTOP) of the current directory that contains Windows 95. This subdirectory is hidden; you can find it by opening a command prompt and typing attrib desktop.

If your system is configured to use a different profile per user, the location of the shortcut is different. You can set up a different profile per user by using the Password applet in Control Panel. Click the User Profiles tab, and then check the "Include desktop icons and Network Neighborhood contents in user settings" option. This will cause the desktop icons (and your desktop shortcut) to be stored in the Desktop subdirectory in the registration database under HKEY_CURRENT_USER/Software/Microsoft/Windows/Current Version/Explorer/Shell Folders. The Desktop key will contain the fully qualified path to the desktop icons. So, for example, if I set up my computer to support per-user profiles, the Desktop key will be under C:/WINDOWS/PROFILES/NANCYCL/DESKTOP.

The link name is completed by retrieving the selected file via a call to DlgDirSelect, stripping off the file extension, and replacing it with the .LNK file extension.

void CreateShortCut::OnOK()
{char szFileSel[MAX_PATH];char szFile[MAX_PATH];char szDesc[MAX_PATH];char szLink[MAX_PATH];DWORD cchCurDir;char* pDot;// First get the path to the link.// Should this shortcut be put on the desktop?if (IsDlgButtonChecked(IDC_CHECK1)){// Yes. Get the directory for Windows Desktop. This is// stored in the Registry under HKEY_CURRENT_USER/Software/// Microsoft/Windows/CurrentVersion/Explorer/Shell Folders/Desktop.HKEY hCU;DWORD lpType;ULONG ulSize = MAX_PATH;if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software//Microsoft//Windows//CurrentVersion//Explorer//Shell Folders", 0,KEY_QUERY_VALUE,&hCU) == ERROR_SUCCESS){RegQueryValueEx( hCU,"Desktop",NULL,&lpType,(unsigned char *)&szLink,&ulSize);RegCloseKey(hCU);}}
else// Get the current directory.GetCurrentDirectory(cchCurDir, szLink);// Get the selected item in the list box.DlgDirSelect(szFile, ID_LBOX);// Get the description.lstrcpy(szDesc, "Shortcut to ");lstrcat(szDesc, strupr(szFile));// Add the forward slash for the path.lstrcat (szLink, "//");// Add the file name.lstrcat (szLink, strupr(szFile));// Strip off the extension, if any.if (pDot = strstr(szLink, "."))*pDot = (char)NULL;// Add in the .LNK extension.lstrcat (szLink, ".LNK");// Get the path to the target.GetCurrentDirectory(cchCurDir, szFileSel);lstrcat(szFileSel, "//");lstrcat(szFileSel, strupr(szFile));// Make call to CreateShortcut() here...CreateIt(szFileSel, szLink, szDesc);// Call the default handler.CDialog::OnOK();
}

Next, we get down to the "real" work of creating the shell link. The CreateIt function actually does the work and takes three parameters:

  • pszShortcutFile: The file that you want the shell link to point to.
  • pszLink: The shell link that you are creating with a .LNK extension.
  • pszDesc: The description of the file. This is the string "Shortcut to <filename>", where filename is the name of the link target.

Because this function makes a call to CoCreateInstance, it is assumed that CoInitialize has already been called. As you can see by the following code, this function uses both the IPersistFile interface for the actual saving of the shell link in the system and the IShellLink interface for storing the path and description information of the link target.

HRESULT CreateShortCut::CreateIt(LPCSTR pszShortcutFile, LPSTR pszLink, LPSTR pszDesc)
{HRESULT hres;IShellLink* psl;// Get a pointer to the IShellLink interface.hres &#61; CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,IID_IShellLink, &psl);if (SUCCEEDED(hres)){IPersistFile* ppf;// Query IShellLink for the IPersistFile interface for // saving the shell link in persistent storage.hres &#61; psl->QueryInterface(IID_IPersistFile, &ppf);if (SUCCEEDED(hres)){ WORD wsz[MAX_PATH];// Set the path to the shell link target.hres &#61; psl->SetPath(pszShortcutFile);if (!SUCCEEDED(hres))AfxMessageBox("SetPath failed!");// Set the description of the shell link.hres &#61; psl->SetDescription(pszDesc);if (!SUCCEEDED(hres))AfxMessageBox("SetDescription failed!");// Ensure string is ANSI.MultiByteToWideChar(CP_ACP, 0, pszLink, -1, wsz, MAX_PATH);// Save the link via the IPersistFile::Save method.hres &#61; ppf->Save(wsz, TRUE);// Release pointer to IPersistFile.ppf->Release();}// Release pointer to IShellLink.psl->Release();}return hres;
}

One thing to bear in mind is that if you create a shell link to another shell link, the system will simply copy the shell link—it won&#39;t create a new shell link. This is important if you are assuming that the shell links will remain independent of each other.

Resolving a Shell Link

Once you have created the shell link, you may need to gain access to and manipulate that link programmatically. This is referred to as "resolving" the shortcut. I added a function to my sample that demonstrates how you can resolve a shell link. Being ever so creative, I decided to use the same type of dialog box that I used for creating the shell link. As such, I used almost exactly the same code to fill the dialog box with the names of the files in the current directory and prompt the user for the link to resolve. The only difference was a simple check to ensure that the user actually picked a .LNK file.

void ResolveShortCut::OnOK()
{char szFile[MAX_PATH];char szPath[MAX_PATH];// Get the current directory.GetCurrentDirectory(MAX_PATH, szPath);// Get the selected item in the list box.DlgDirSelect( szFile, IDC_LIST1);// Find out if it is a .LNK file or not.if (strstr(szFile, ".lnk") !&#61; NULL)// Make call to ResolveShortcut here.ResolveIt(m_hWnd, szFile, szPath );CDialog::OnOK();
}

This shortcut resolving function takes three parameters:

  • hwnd: The handle to the current focus window. We need this in case the shell needs to display a message box prompting the user to do something. This box will be displayed if the user needs to insert a floppy disk, if the link is on unshared media, or if there are network problems during the resolution of the shell link.
  • SzShortcutFile: The fully qualified path to the shell link.
  • CchPath: The size of the return buffer.

As with my function that created the shell link, this function calls CoCreateInstance and assumes that CoInitialize has been called already. Notice that the code below needs to call into the IPersistFile interface. This interface is implemented by the IShellLink object to store link information. To get the path information that I query later in the code, I need to have the link information loaded first. Failing to load the link information would cause my calls to GetPath and GetDescription to fail.

HRESULT ResolveShortCut::ResolveIt(HWND hwnd, LPCSTR pszShortcutFile, LPSTR pszPath)
{HRESULT hres;IShellLink* psl;char szGotPath[MAX_PATH];char szDescription[MAX_PATH];WIN32_FIND_DATA wfd;*pszPath &#61; 0; // assume failure// Get a pointer to the IShellLink interface.hres &#61; CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,IID_IShellLink, &psl);if (SUCCEEDED(hres)){IPersistFile* ppf;// Get a pointer to the IPersistFile interface.hres &#61; psl->QueryInterface(IID_IPersistFile, &ppf);if (SUCCEEDED(hres)){WORD wsz[MAX_PATH];// Ensure string is Unicode.MultiByteToWideChar(CP_ACP, 0, pszShortcutFile, -1, wsz,MAX_PATH);// Load the shell link.hres &#61; ppf->Load(wsz, STGM_READ);if (SUCCEEDED(hres)){// Resolve the link.hres &#61; psl->Resolve(hwnd, SLR_ANY_MATCH);if (SUCCEEDED(hres)){strcpy(szGotPath, pszShortcutFile);// Get the path to the link target.hres &#61; psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATA *)&wfd, SLGP_SHORTPATH );if (!SUCCEEDED(hres)AfxMessageBox("GetPath failed!");// Get the description of the target. hres &#61; psl->GetDescription(szDescription, MAX_PATH);if (!SUCCEEDED(hres))AfxMessageBox("GetDescription failed!");}}// Release pointer to IPersistFile interface.ppf->Release();}// Release pointer to IShellLink interface.psl->Release();}return hres;
}

Creating a Link to Something Other Than a File

The above code demonstrates how you can programmatically create a link to a file, but it does not cover the steps that you must take to create a link to something that does not have a filename, such as a printer or Control Panel. From the standpoint of creating the shell link, the major difference lies in the fact that rather than setting the path to the link, you will instead be setting the identification list (ID List) to the printer. This is done by calling the IShellLink::SetIDList method and providing a pointer to an ID List (pidl).

I know what you are thinking. "What the heck is an ID List?"

All objects within the shell name space have an item identifier, known as an Item ID. This identifier is a variable-length byte stream containing information that identifies the object within a folder. The shell often concatenates Item IDs together to form a list of IDs, known as ID Lists. These lists may contain one or many Item IDs and are NULL terminated.

Using MFC

If you plan to use the CreateIt function from the SHORTCUT sample in your MFC-based application, you may run into problems with the conversion from multibyte to wide characters. If you do, search for "Technical Note 49: MFC/OLE MBCS to Unicode Translation Layer (MFCANS32)" in the MSDN Library. The MFCANS32 DLL provides ANSI interfaces to 32-bit OLE, which is primarily Unicode. This technical note will show you what you need to do if you experience this problem.

Summary

This article gives you the bare-bones information you need to create and resolve shell links within an application. It is by no means an all-encompassing work, though. If you would like to learn more about the underpinnings of shell links, my advice is to read the next article in the series on shell links, "The IShellLink Interface."

 

转:https://www.cnblogs.com/xkxjy/archive/2009/04/25/3672280.html



推荐阅读
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了在Mac上安装Xamarin并使用Windows上的VS开发iOS app的方法,包括所需的安装环境和软件,以及使用Xamarin.iOS进行开发的步骤。通过这种方法,即使没有Mac或者安装苹果系统,程序员们也能轻松开发iOS app。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • 如何搭建Java开发环境并开发WinCE项目
    本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • 树莓派语音控制的配置方法和步骤
    本文介绍了在树莓派上实现语音控制的配置方法和步骤。首先感谢博主Eoman的帮助,文章参考了他的内容。树莓派的配置需要通过sudo raspi-config进行,然后使用Eoman的控制方法,即安装wiringPi库并编写控制引脚的脚本。具体的安装步骤和脚本编写方法在文章中详细介绍。 ... [详细]
  • 解决github访问慢的问题的方法集锦
    本文总结了国内用户在访问github网站时可能遇到的加载慢的问题,并提供了解决方法,其中包括修改hosts文件来加速访问。 ... [详细]
  • 修复安装win10失败并提示“磁盘布局不受UEFI固件支持”的方法
    本文介绍了修复安装win10失败并提示“磁盘布局不受UEFI固件支持”的方法。首先解释了UEFI的概念和作用,然后提供了两种解决方法。第一种方法是在bios界面中将Boot Mode设置为Legacy Support,Boot Priority设置为Legacy First,并关闭UEFI。第二种方法是使用U盘启动盘进入PE系统,运行磁盘分区工具DiskGenius,将硬盘的分区表设置为gpt格式,并留出288MB的内存。最后,通过运行界面输入命令cmd来完成设置。 ... [详细]
  • React基础篇一 - JSX语法扩展与使用
    本文介绍了React基础篇一中的JSX语法扩展与使用。JSX是一种JavaScript的语法扩展,用于描述React中的用户界面。文章详细介绍了在JSX中使用表达式的方法,并给出了一个示例代码。最后,提到了JSX在编译后会被转化为普通的JavaScript对象。 ... [详细]
author-avatar
云妹12241999
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有