unit ShlFunc; {本单元可使用尽可能少的资源完成下面的功能}<br>interface<br>const<br>//用于描述系统文件夹的前缀常量<br> nvF_PgmMenu = #$82; // [开始][程序]<br> nvF_MyDoc = #$85; // 我的文档<br> nvF_BookMrk = #$86; // 收藏夹<br> nvF_Startup = #$87; // [开始][启动]<br> nvF_Recent = #$88; // [开始][文档]<br> nvF_SendTo = #$89; // 发送到...<br> nvF_StrMenu = #$8B; // [开始]<br> nvF_Desktop = #$90; // 桌面<br><br> nvF_Windows = #$A0; // Windows<br> nvF_System = #$A1; // Windows/System<br> nvF_Temp = #$A2; // Temp Directory<br><br> nvF_PgmFile = #$A3; // Program Files<br> nvF_PgmComm = #$A4;<br> nvF_AppData = #$A5; // Application Data<br>//-----------------------------------------<br> nvF_ProgramMenu = nvF_PgmMenu;<br> nvF_MyDocuments = nvF_MyDoc;<br> nvF_Favorites = nvF_Bookmrk;<br> nvF_Bookmark = nvF_Bookmrk;<br> nvF_StartMenu = nvF_StrMenu;<br> nvF_ProgramFile = nvF_PgmFile;<br> nvF_CommonFile = nvF_PgmComm;<br> nvF_ApplicationData = nvF_AppData;<br>{/-----------------------------------------<br>===============================================================================<br>取系统文件夹, nvFolder 为上述常数, 可返回短文件名}<br>function GetSysFolder(nvFolder: Char; ShortPath: Boolean): String;<br>function DoGetSysFolder(nvFolder: Char; ShortPath: Boolean; var S: String): Integer; // 返回长度<br>{<br>展开如 nvF_Desktop+'MyFolder/MySubFolder' 的路径名, 结果可用 ExpandedPathName 变量访问}<br>function GetExpandPathName(const xPath: String): String;<br>function DoExpandPathName(const xPath: String): Integer; // 返回长度<br>{<br>搜索文件夹, 可返回短文件名, hWnd可以是0(nil)或调用窗口的Handle}<br>function SearchPaths(hWND: Integer; const Title: String; ShortPath: Boolean): String;<br>{<br>创建快捷方式(ShortCutName可描述为 nvF_xxx+'.../.../YYY" )<br>如果ShortCutName='' 那么加入到[开始][文档], 成功返回实际的lnk文件名长度, 失败返回0}<br>function CreateFileShortCut(const FileName, ShortCutName: String): Integer;<br>{<br>通用字符串函数(从Src中的第SrcId个开始拷贝Count个字符到Tar的TarId开始的位置, 返回目标串的长度)<br>该函数可避免频繁的字符串内存重分配<br>SrcId, TarId, Count都可以为0, TarId=0 时将在Tar后面连接Src, Count=0 时将一直复制到Src的结尾}<br>function StrCopyEx(const Src: String; var Tar: String; SrcId, TarId, Count: Integer): Integer;<br>{<br>取文件的短文件名}<br>function DOSFileName(const FileName: String): String;<br>function FileName8_3(var FileName: String): Integer; // 返回长度<br>{<br>路径是否存在, 如果AutoCreate, 那么如果路径不存在则自动创建}<br>function PathExists(const xPath: String; AutoCreate: Boolean): Boolean;<br>{<br>把文件删除到回收站}<br>procedure EraseToRecyle(const FileName: String);<br><br>var<br> ExpandedPathName: string;<br>///////////////////////////////////////////////////////////////////////////////<br>implementation<br><br>uses<br> ShellAPI, ShlObj, Windows;<br><br>var<br> pxBrowse: PBrowseInfoA;<br> pxItemID: PItemIDList;<br> BrowseDlgTitle: String;<br>{<br>===============================================================================<br>}<br>function StrCopyEx(const Src: String; var Tar: String; SrcId, TarId, Count: Integer): Integer;<br>var<br> I: Integer;<br>begin<br> if SrcId <= 0 then SrcId:= 0 else Dec(SrcId);<br> if Count <= 0 then Count:= Length(Src) - SrcId;<br> if TarId <= 0 then TarId:= Length(Tar) else Dec(TarId);<br> Result:= TarId + Count;<br> if Result > Length(Tar) then SetLength(Tar, Result);<br> for I:= 1 to Count do Tar[TarId + I]:= Src[SrcId + I];<br>end;<br>{<br>===============================================================================<br>}<br>function DOSFileName(const FileName: String): String;<br>begin<br> Result:= FileName;<br> SetLength(Result, FileName8_3(Result));<br>end;<br><br>function FileName8_3(var FileName: String): Integer;<br>begin<br> try<br> Result:= GetShortPathName(PChar(FileName), @FileName[1], Length(FileName));<br> if Result < Length(FileName) then FileName[Result+1]:= #0;<br> except<br> Result:= 0;<br> end;<br>end;<br>{<br>===============================================================================<br>}<br>function GetExpandPathName(const xPath: String): String;<br>var<br> I, X: Integer;<br>begin<br> X:= DoExpandPathName(xPath);<br> SetLength(Result, X);<br> for I:= 1 to X do Result:= ExpandedPathName;<br>end;<br><br>function DoExpandPathName(const xPath: String): Integer;<br>begin<br> if Ord(xPath[1]) < $80 then begin<br> ExpandedPathName:= xPath + #0;<br> Result:= Length(xPath);<br> end else begin<br> if Length(ExpandedPathName) < 255 then SetLength(ExpandedPathName, 255);<br> Result:= DoGetSysFolder(xPath[1], false, ExpandedPathName);<br> Result:= StrCopyEx(xPath, ExpandedPathName, 2, Result+1, 0);<br> ExpandedPathName[Result+1]:= #0;<br> end;<br>end;<br><br>function PathExists(const xPath: String; AutoCreate: Boolean): Boolean;<br>var<br> X: Integer;<br>procedure CreatePaths;<br>var<br> I: Integer; ch: char;<br>begin<br> for I:= 1 to Length(ExpandedPathName) do begin<br> ch:= ExpandedPathName;<br> if ch = #0 then Break;<br> if ch <> '/' then Continue;<br><br> ch:= ExpandedPathName[I+1];<br> ExpandedPathName[I+1]:= #0;<br> X:= GetFileAttributes(@ExpandedPathName[1]);<br> ExpandedPathName[I+1]:= ch;<br> if (X <> -1) and (FILE_ATTRIBUTE_DIRECTORY and X <> 0) then Continue;<br><br> ExpandedPathName:= #0;<br> CreateDirectory(@ExpandedPathName[1], nil);<br> ExpandedPathName:= '/';<br> end;<br>end;<br><br>begin<br> DoExpandPathName(xPath);<br> X:= GetFileAttributes(@ExpandedPathName[1]);<br> Result:= (X <> -1) and (FILE_ATTRIBUTE_DIRECTORY and X <> 0);<br> if Result or (not AutoCreate) then Exit;<br> try CreatePaths; Result:= True; except end;<br>end;<br>{<br>===============================================================================<br>}<br>function GetSysFolder(nvFolder: Char; ShortPath: Boolean): String;<br>begin<br> SetLength(Result, 255);<br> SetLength(Result, DoGetSysFolder(nvFolder, ShortPath, Result));<br>end;<br><br>function DoGetSysFolder(nvFolder: Char; ShortPath: Boolean; var S: String): Integer;<br>var<br> X: Integer;<br>procedure zReadRegistry(const KeyName: String);<br>var<br> phk: HKEY;<br>begin<br> PShortString(X):= @S[1]; PShortString(X)^:= 'Software/Microsoft/Windows/CurrentVersion/Explorer/Shell Folders'#0;<br> if KeyName[1] = '/' then begin //01234567890123456789012345678901234567890123<br> S[43]:= #0; X:= HKEY_LOCAL_MACHINE; //0---------1---------2---------3---------4---<br> end else X:= HKEY_CURRENT_USER; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<br> if RegOpenKeyEx(X, @S[2], 0, KEY_QUERY_VALUE, phk) = ERROR_SUCCESS then begin<br> X:= Length(S);<br> if RegQueryValueEx(phk, @KeyName[2], nil, nil, @S[1], Addr(X)) = ERROR_SUCCESS then Dec(X) else X:= 0;<br> end else X:= 0;<br>end;<br>begin Result:= 0; try<br> X:= Ord(nvFolder);<br> if X < $A0 then begin<br> if SHGetSpecialFolderLocation(0, (X and $7F), pxItemID) <> NOERROR then Exit;<br> if pxItemID = nil then Exit;<br> if not SHGetPathFromIDList(pxItemID, @S[1]) then Exit;<br> X:= Pos(#0, S) - 1;<br> end else case nvFolder of<br> nvF_Windows: X:= GetWindowsDirectory(@S[1], 255);<br> nvF_System : X:= GetSystemDirectory(@S[1], 255);<br> nvF_Temp : X:= GetTempPath(255, @S[1]);<br> nvF_PgmFile: zReadRegistry('/ProgramFilesDir'#0);<br> nvF_PgmComm: zReadRegistry('/CommonFilesDir'#0);<br> nvF_AppData: zReadRegistry('.AppData'#0);<br> end; {case}<br> if X = 0 then Exit;<br> if ShortPath then X:= FileName8_3(S);<br> if S[X] <> '/' then begin Inc(X); S[X]:= '/'; end;<br> Result:= X; S[X+1]:= #0;<br>except Exit; end; end;<br>{<br>===============================================================================<br>}<br>function CreateFileShortCut(const FileName, ShortCutName: String): Integer;<br>var<br> X: Integer; S: String;<br>begin Result:= 0; try<br> //首先在"文档"里创建快捷方式, 如不指定目标则算完成<br> SHAddToRecentDocs(SHARD_PATH, PChar(FileName));<br> if Length(ShortCutName) = 0 then begin Dec(Result); Exit; end;<br><br> //取文件名的开始<br> for X:= Length(FileName) downto 1 do<br> if FileName[X] = '/' then begin Result:= X; Break; end;<br><br> //取源文件名("文档"菜单的路径)<br> SetLength(S, 255);<br> SHGetSpecialFolderLocation(0, CSIDL_RECENT, pxItemID);<br> SHGetPathFromIDList(pxItemID, @S[1]);<br> X:= Pos(#0, S); if S[X-1] <> '/' then begin S[X]:= '/'; Inc(X); end;<br><br> X:= StrCopyEx(FileName, S, Result + 1, X, 0) + 1;<br> Result:= 0; PShortString(@S[X])^:= 'lnk'#0; S[X]:= '.';<br><br> //定位目标文件<br> X:= DoExpandPathName(ShortCutName);<br> if not PathExists(ExpandedPathName, True) then Exit;<br> Result:= StrCopyEx('.lnk'#0, ExpandedPathName, 0, X+1, 0);<br> if CopyFile(@S[1], @ExpandedPathName[1], False) then DeleteFile(@S[1]);<br>except Result:= 0; end;<br>end;<br>{<br>===============================================================================<br>}<br>procedure InitBrowseInfo(hWND: Integer);<br>begin<br> if pxBrowse = nil then New(pxBrowse);<br> with pxBrowse^ do begin<br> hWndOwner:= hWND;<br> pidlRoot:= nil;<br> pszDisplayName:= nil;<br><br> lpszTitle:= @BrowseDlgTitle[1];<br> ulFlags:= BIF_RETURNONLYFSDIRS;<br> lpfn:= nil;<br> end;<br>end;<br>{<br>===============================================================================<br>}<br>function SearchPaths(hWND: Integer; const Title: String; ShortPath: Boolean): String;<br>begin SetLength(Result, 0); try;<br> if Length(Title) > 0 then BrowseDlgTitle:= Title + #0;<br> InitBrowseInfo(hWND);<br> pxItemID:= SHBrowseForFolder(pxBrowse^);<br> Dispose(pxBrowse); pxBrowse:= nil;<br> if pxItemID = nil then Exit;<br><br> SetLength(Result, 255);<br> SHGetPathFromIDList(pxItemID, @Result[1]);<br> if ShortPath then hWND:= FileName8_3(Result) else hWND:= Pos(#0, Result) - 1;<br> if Result[hWND] <> '/' then begin Inc(hWND); Result[hWND]:= '/'; end;<br> SetLength(Result, hWND);<br>except SetLength(Result, 0); end; end;<br><br>procedure EraseToRecyle(const FileName: String);<br>{ 利用ShellApi中: function SHFileOperation(const lpFileOp:TSHFileOpStruct): Integer; stdcall; }<br>var<br> T: TSHFileOpStruct;<br>begin<br> with T do begin<br> Wnd:=0;<br> wFunc:=FO_DELETE;<br> pFrom:=Pchar(FileName);<br> fFlags:=FOF_ALLOWUNDO<br> end;<br> SHFileOperation(T);<br>end;<br>{<br>===============================================================================<br>}<br>initialization<br> BrowseDlgTitle:= '搜索文件夹'#0;<br> SetLength(ExpandedPathName, 0);<br> pxBrowse:= nil;<br>finalization<br> if pxBrowse <> nil then Dispose(pxBrowse);<br>end.<br>