C 程序员通常都会使用 IShellLink 来创建快捷方式,但 vfp 没有这么幸运,虽然可以用 CoCreateInstance 创建出一个 IShellLink 界面对象,可是却无法调用这种 COM 对象提供的方法,原因可以参见 这里。所以一直以来都没有非常好的编程创建快捷方式的方法。
常用方法是使用安装程序提供方法来在安装时创建它,可如果做成绿色版,就没这个方便性了,于是利用编程动态创建快捷方式的方法就变成了需要解决的一个问题。归纳起来,无外乎下面几种方法:
1. 利用 wsh 提供的方法
2. 利用第三方控件或函数库(dll / fll)
3. 利用 shell 提供的对象
其中利用 wsh 的方法比较常用,唯一缺点是现在病毒的猖獗导致很多管理员不得不禁用了系统的 wsh,如果只是删除掉与 vbs 等脚本的关联倒也无所谓,我们是直接创建 wsh 对象,不会受它的影响,然而也有些管理员是将 wsh 卸载的,或者用 regsvr32/u wshom.ocx 方式注销掉它的,这将导致此方法的失效。
利用第三方控件方法的缺点是需要随软件一同发布这个控件或库文件,感觉为了一个创建快捷方式来增加一个 dll,不值!好在 vb6 提供的 vb6stkit.dll 提供了一个函数可以完成此功能,绝大部分机器上都可以找到这个控件,基本不需另外发行。但也有个缺点,它的快捷方式存放的位置必须指定相对路径,而且相对路径的写法也十分怪异!(见示例中的 CreateShortcut2 ),很多人都无法正确的使用它,我也是费了半个钟头才算基本搞清楚它。
利用 shell 的方法是刚摸索出来的,示例中的 CreateShortcut3 演示了它的实现方法,好处是不需要发行任何外部 dll/fll,也不受禁用 wsh 的影响,直接使用系统文件 shell32.dll 提供的对象来实现,其实跟使用 IShellLink 接口来实现使用的是同一个文件,只是绕了一个弯,速度也是三种方法中最快的。缺点嘛,暂时还没发现,不知道是否可以用于 Win9x/Me,没有环境测试。
另外还有一种比较另类的方法,就是像创建网页快捷方式一样,创建 url 文件,如果程序只是为了创建一个桌面图标来达到快速选择的话,也是一种不错的选择,只是它并非真正意义上的 Windows 快捷方式,功能要少很多,右击选“属性”对比一下就知道了。
下面是示例代码,功能是在桌面上创建记事本的快捷方式:
- CLEAR
- *!* -------------------------------------------------
- m.cFile = 'c:/windows/notepad.exe' && 2000 改为 c:/winnt/notepad.exe
- *!* -------------------------------------------------
- m.s = SECONDS()
- ? CreateShortcut1( m.cFile, 'wsh 创建的快捷方式' ), SECONDS() - m.s
- m.s = SECONDS()
- ? CreateShortcut2( m.cFile, 'vbstkit 创建的快捷方式' ), SECONDS() - m.s
- m.s = SECONDS()
- ? CreateShortcut3( m.cFile, 'shell 创建的快捷方式' ), SECONDS() - m.s
- m.s = SECONDS()
- ? CreateShortcut4( m.cFile, 'url 创建的快捷方式' ), SECONDS() - m.s
- *!* -------------------------------------------------
- *!* 利用 wsh 创建
- *!* -------------------------------------------------
- FUNCTION CreateShortcut1( tcExeFile, tcLinkName )
- LOCAL oWsh, oLnk, cDesktop
- TRY
- m.oWsh = CreateObject( 'WScript.Shell' )
- CATCH
- m.oWsh = NULL
- ENDTRY
- IF ISNULL( m.oWsh )
- RETURN .F.
- ELSE
- m.cDesktop = m.oWsh.SpecialFolders( 'Desktop' )
- m.oLnk = m.oWsh.CreateShortcut( m.cDesktop + '/' + m.tcLinkName + '.lnk' )
- m.oLnk.TargetPath = m.tcExeFile
- m.oLnk.Save()
- ENDIF
- ENDFUNC
- *!* -------------------------------------------------
- *!* 利用 vb6stkit.dll 创建
- *!* -------------------------------------------------
- FUNCTION CreateShortcut2( tcExeFile, tcLinkName )
- LOCAL cOldDir, cFolder, lOK
- TRY
- DECLARE Long fCreateShellLink IN vb6stkit ;
- String lpstrFolderName, String lpstrLinkName, ;
- String lpstrLinkPath, String lpstrLinkArguments, ;
- Long fPrivate, String sParent
- m.lOK = .T.
- CATCH
- m.lOK = .F.
- ENDTRY
- IF ( m.lOK )
- m.cOldDir = SYS(5) + CURDIR()
- m.cFolder = GETENV( 'USERPROFILE' )
- m.cFolder = STRTRAN( m.cFolder, JUSTDRIVE( m.cFolder ), '' )
- SET DEFAULT TO c:/
- m.lOK = ( 0 != fCreateShellLink( ;
- '../../../../' + m.cFolder + '/桌面', ;
- m.tcLinkName, m.tcExeFile, '', 0, '' ))
- SET DEFAULT TO ( m.cOldDir )
- ENDIF
- RETURN m.lOK
- ENDFUNC
- *!* -------------------------------------------------
- *!* 利用 shell 对象创建(原创)
- *!* -------------------------------------------------
- FUNCTION CreateShortcut3( tcExeFile, tcLinkName )
- LOCAL oShell, oFolder, oFile
- m.oShell = CREATEOBJECT( 'Shell.Application' )
- m.oFolder = m.oShell.NameSpace( 0 )
- STRTOFILE( '', m.oFolder.Self.Path + '/' + m.tcLinkName + '.lnk' )
- m.oFile = m.oFolder.ParseName( m.tcLinkName + '.lnk' )
- IF ISNULL( m.oFile )
- RETURN .F.
- ELSE
- WITH m.oFile.GetLink()
- .SetIconLocation( m.tcExeFile, 0 )
- .Path = m.tcExeFile
- .WorkingDirectory = JUSTPATH( m.tcExeFile )
- .Save()
- ENDWITH
- ENDIF
- ENDFUNC
- *!* -------------------------------------------------
- *!* 利用 url 创建
- *!* -------------------------------------------------
- FUNCTION CreateShortcut4( tcExeFile, tcLinkName )
- LOCAL cLink, cFile
- TEXT TO m.cLink NOSHOW TEXTMERGE
- [InternetShortcut]
- URL=<<m.tcExeFile>>
- IconIndex=0
- IconFile=<<m.tcExeFile>>
- ENDTEXT
- m.cFile = GETENV( 'USERPROFILE' ) + '/桌面/' + m.tcLinkName + '.url'
- STRTOFILE( m.cLink, m.cFile )
- ENDFUNC