热门标签 | 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



推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • Oracle seg,V$TEMPSEG_USAGE与Oracle排序的关系及使用方法
    本文介绍了Oracle seg,V$TEMPSEG_USAGE与Oracle排序之间的关系,V$TEMPSEG_USAGE是V_$SORT_USAGE的同义词,通过查询dba_objects和dba_synonyms视图可以了解到它们的详细信息。同时,还探讨了V$TEMPSEG_USAGE的使用方法。 ... [详细]
  • 基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
    文章目录引言开发环境和库流程设计张嘴和闭眼的检测引言(1)利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68个点标定 ... [详细]
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社区 版权所有