Die ausführbare Datei eines "advertised shortcut" ermitteln
Worum geht es?
Zuerst einmal: Was ist überhaupt ein solcher "advertised shortcut"? - Das ist eine besondere Art Shortcut, welche z.B. von OpenOffice 2.0 verwendet wird. Er zeigt nicht mehr, wie die "normalen" Shortcuts im Startmenü, auf die ausführbare Datei des Programmes, sondern geht über den Microsoft Installer. Ein solcher Shortcut macht es z.B. möglich, dass ein Programm installiert wird, wenn das erste Mal aufgerufen wird.
Leider kann man einen solchen Shortcut nicht mehr per Übergabe an
SHELLEXECUTE ausführen, wie es mit normalen Shortcuts geht. Man muss ein wenig mehr Aufwand treiben.
Die Lösung
Vorne weg einfach schon mal den Quellcode. Vieles davon stammt aus verschiedenen Quellen, meine Arbeit steckt in der Prozedur "getExecData". Da der Rest recht mühsam zusammen zu suchen ist, gebe ich ihn mit
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149:
| unit getAdvShortcut;
interface
uses ShlObj, ComObj, ActiveX, CommCtrl, Windows, SysUtils;
procedure getExecData(lnkName : String; var execName, execDir, execArgs : String);
implementation
type TCharArray = Array[0..MAX_PATH] of Char;
type PShellLinkInfoStruct = ^TShellLinkInfoStruct; TShellLinkInfoStruct = record FullPathAndNameOfLinkFile: TCharArray; FullPathAndNameOfFileToExecute: TCharArray; ParamStringsOfFileToExecute: TCharArray; FullPathAndNameOfWorkingDirectroy: TCharArray; Description: TCharArray; FullPathAndNameOfFileContiningIcon: TCharArray; IconIndex: Integer; HotKey: Word; ShowCommand: Integer; FindData: TWIN32FINDDATA; end;
const MsiDllName = 'msi.dll';
INSTALLSTATE_ABSENT = 2; INSTALLSTATE_LOCAL = 3; INSTALLSTATE_SOURCE = 4; INSTALLSTATE_SOURCEABSENT = -4; INSTALLSTATE_NOTUSED = -7; INSTALLSTATE_INVALIDARG = -2; INSTALLSTATE_UNKNOWN = -1; type INSTALLSTATE = LongInt;
TMsiGetShortcutTarget = function(szShortcutTarget, szProductCode, szFeatureId, szComponentCode: PAnsiChar): uint; stdcall; TMsiGetComponentPath = function(szProduct, szComponent: PAnsiChar; lpPathBuf: PAnsiChar; pcchBuf: pdword): INSTALLSTATE; stdcall; var MsiGetShortcutTarget : TMsiGetShortcutTarget = nil; MsiGetComponentPath : TMsiGetComponentPath = nil; MsiDll : dword = 0;
procedure GetLinkInfo(lpShellLinkInfoStruct: PShellLinkInfoStruct); var ShellLink: IShellLink; PersistFile: IPersistFile; AnObj: IUnknown; begin AnObj := CreateComObject(CLSID_ShellLink); ShellLink := AnObj as IShellLink; PersistFile := AnObj as IPersistFile;
PersistFile.Load(PWChar(WideString(lpShellLinkInfoStruct^.FullPathAndNameOfLinkFile)), 0);
with ShellLink do begin GetPath(lpShellLinkInfoStruct^.FullPathAndNameOfFileToExecute, SizeOf(lpShellLinkInfoStruct^.FullPathAndNameOfLinkFile), lpShellLinkInfoStruct^.FindData, SLGP_UNCPRIORITY);
GetWorkingDirectory(lpShellLinkInfoStruct^.FullPathAndNameOfWorkingDirectroy, SizeOf(lpShellLinkInfoStruct^.FullPathAndNameOfWorkingDirectroy));
GetArguments(lpShellLinkInfoStruct^.ParamStringsOfFileToExecute, SizeOf(lpShellLinkInfoStruct^.ParamStringsOfFileToExecute)); end; end;
procedure getExecData(lnkName : String; var execName, execDir, execArgs : String); var LinkInfo: TShellLinkInfoStruct; aFile : TCharArray; prodCode, featureId, compCode : TCharArray; aPath : TCharArray; pathLength : DWord; begin FillChar(LinkInfo, SizeOf(LinkInfo), #0); StrCopy(@aFile, PChar(lnkName)); LinkInfo.FullPathAndNameOfLinkFile := aFile; GetLinkInfo(@LinkInfo); execName := LinkInfo.FullPathAndNameOfFileToExecute; execDir := LinkInfo.FullPathAndNameOfWorkingDirectroy; execArgs := LinkInfo.ParamStringsOfFileToExecute;
ZeroMemory(@prodCode, sizeOf(prodCode)); ZeroMemory(@featureId, sizeOf(featureId)); ZeroMemory(@compCode, sizeOf(compCode)); if MsiGetShortcutTarget(aFile, prodCode, featureId, compCode) = ERROR_SUCCESS then begin pathLength := sizeOf(aPath); ZeroMemory(@aPath, sizeOf(aPath)); if MsiGetComponentPath(prodCode, compCode, aPath, @pathLength) = INSTALLSTATE_LOCAL then execName := aPath; end; end;
initialization MsiDll := GetModuleHandle(MsiDllName); if(MsiDll = 0) then MsiDll := LoadLibrary(MsiDllName);
if(MsiDll <> 0) then begin MsiGetShortcutTarget := GetProcAddress(MsiDll, 'MsiGetShortcutTargetA'); MsiGetComponentPath := GetProcAddress(MsiDll, 'MsiGetComponentPathA');
if(@MsiGetShortcutTarget = nil) or (@MsiGetComponentPath = nil) then begin FreeLibrary(MsiDll); MsiDll := 0; end; end;
finalization if(MsiDll <> 0) then FreeLibrary(MsiDll);
end. |
Der Prozedur
getExecData übergibt man in
lnkName den Dateinamen eines beliebigen Shortcuts, egal ob "advertised" oder nicht. Sie gibt dann den Namen der ausführbaren Datei, das Arbeitsverzeichnis und die Parameter zurück. Diese können dann bequem an
ShellExecute übergeben werden.
Die Prozedur arbeitet so, dass sie mittels eines Codes von swissdelphicenter.ch die Daten eines "herkömmlichen" Shortcuts ausliest. Bei einem advertised Shortcut stimmen dabei aber nur Parameter und Arbeitsverzeichnis, jedoch nicht die ausführbare Datei. Daher ändert diese Prozedur die ausführbare Datei nachträglich, wenn es sich um einen advertised Shortcut handelt und das Programm auch installiert ist.
Referenzen
SwissDelphiCenter.ch - ...Informationen aus einer Verknüpfungsdatei (*.lnk) auslesen ?
MSDN Library - Installer Function Reference - MsiGetShortcutTarget
MSDN Library - Installer Function Reference - MsiGetComponentPath
Delphi-Forum.de (diverse Autoren, siehe Source) - TFolderBrowser
Der verwendete Code beruht auf oben genannten, frei zugänglichen Quellen, sodass eine freie Verwendung ohne Probleme möglich ist.
Ich hoffe, damit ein paar Leuten geholfen zu haben
Grüße
Christian
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".