⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 instfnc2.pas

📁 源代码
💻 PAS
字号:
unit InstFnc2;

{
  Inno Setup
  Copyright (C) 1997-2004 Jordan Russell
  Portions by Martijn Laan
  For conditions of distribution and use, see LICENSE.TXT.

  OLE-related installation functions

  $jrsoftware: issrc/Projects/InstFnc2.pas,v 1.18 2004/09/01 21:42:12 jr Exp $
}

interface

{$I VERSION.INC}

function CreateShellLink(const Filename, Description, ShortcutTo, Parameters,
  WorkingDir, IconFilename: String; const IconIndex, ShowCmd: Integer;
  const HotKey: Word; FolderShortcut: Boolean): String;
procedure RegisterTypeLibrary(const Filename: String);
function UnregisterTypeLibrary(const Filename: String): Boolean;

implementation

uses
  Windows, SysUtils, PathFunc, CmnFunc2, Main, Msgs, MsgIDs,
  {$IFNDEF Delphi3orHigher} OLE2, {$ELSE} ActiveX, ComObj, {$ENDIF}
  ShellAPI, ShlObj;

procedure RaiseOleError(const FunctionName: String; const ResultCode: HRESULT);
begin
  raise Exception.Create(FmtSetupMessage(msgErrorFunctionFailedWithMessage,
    [FunctionName, IntToHexStr8(ResultCode), Win32ErrorString(ResultCode)]));
end;

function IsWindowsXP: Boolean;
{ Returns True if running Windows XP or later }
begin
  Result := (WindowsVersion >= $05010000);
end;

function GetResultingFilename(const PF: IPersistFile;
  const OriginalFilename: String): String;
{ Determines the actual resulting filename. IPersistFile::Save doesn't always
  save to the specified filename; it may rename the extension to .pif if the
  shortcut points to an MS-DOS application. }
var
  CurFilename: PWideChar;
  OleResult: HRESULT;
begin
  Result := '';
  CurFilename := nil;
  OleResult := PF.GetCurFile(CurFilename);
  { Note: Prior to Windows 2000/Me, GetCurFile succeeds but returns a NULL
    pointer }
  if SUCCEEDED(OleResult) and Assigned(CurFilename) then begin
    if OleResult = S_OK then
      Result := WideCharToString(CurFilename);
    CoTaskMemFree(CurFilename);
  end;
  { If GetCurFile didn't work (e.g. not running Windows 2000/Me or later), we
    have no choice but to try to guess the filename }
  if Result = '' then begin
    if NewFileExists(OriginalFilename) then
      Result := OriginalFilename
    else if NewFileExists(PathChangeExt(OriginalFilename, '.pif')) then
      Result := PathChangeExt(OriginalFilename, '.pif')
    else begin
      { Neither exist? Shouldn't happen, but return something anyway }
      Result := OriginalFilename;
    end;
  end;
end;

function CreateShellLink(const Filename, Description, ShortcutTo, Parameters,
  WorkingDir, IconFilename: String; const IconIndex, ShowCmd: Integer;
  const HotKey: Word; FolderShortcut: Boolean): String;
{ Creates a lnk file named Filename, with a description of Description, with a
  HotKey hotkey, which points to ShortcutTo.
  NOTE! If you want to copy this procedure for use in your own application
  be sure to call CoInitialize at application startup and CoUninitialize at
  application shutdown. See the bottom of this unit for an example. But this
  is not necessary if you are using Delphi 3 and your project already 'uses'
  the ComObj RTL unit. }
const
  CLSID_FolderShortcut: TGUID = (
    D1:$0AFACED1; D2:$E828; D3:$11D1; D4:($91,$87,$B5,$32,$F1,$E9,$57,$5D));
{$IFNDEF Delphi3OrHigher}
var
  OleResult: HRESULT;
  SL: IShellLink;
  PF: IPersistFile;
  WideFilename: PWideChar;
begin
  if FolderShortcut then
    OleResult := CoCreateInstance(CLSID_FolderShortcut, nil, CLSCTX_INPROC_SERVER,
      IID_IShellLink, SL)
  else
    OleResult := E_FAIL;
  { If a folder shortcut wasn't requested, or if CoCreateInstance failed
    because the user isn't running Windows 2000/Me or later, create a normal
    shell link instead }
  if OleResult <> S_OK then begin
    FolderShortcut := False;
    OleResult := CoCreateInstance(CLSID_ShellLink, nil, CLSCTX_INPROC_SERVER,
       IID_IShellLink, SL);
    if OleResult <> S_OK then
      RaiseOleError('CoCreateInstance', OleResult);
  end;
  PF := nil;
  WideFilename := nil;
  try
    SL.SetPath(PChar(ShortcutTo));
    SL.SetArguments(PChar(Parameters));
    if WorkingDir <> '' then
      SL.SetWorkingDirectory(PChar(WorkingDir));
    if IconFilename <> '' then
      SL.SetIconLocation(PChar(IconFilename), IconIndex);
    SL.SetShowCmd(ShowCmd);
    if Description <> '' then
      SL.SetDescription(PChar(Description));
    if HotKey <> 0 then
      SL.SetHotKey(HotKey);

    OleResult := SL.QueryInterface(IID_IPersistFile, PF);
    if OleResult <> S_OK then
      RaiseOleError('IShellLink::QueryInterface', OleResult);
    { When creating a folder shortcut on 2000/Me, IPersistFile::Save will strip
      off everything past the last '.' in the filename, so we keep the .lnk
      extension on to give it something harmless to strip off. XP doesn't do
      that, so we must remove the .lnk extension ourself. }
    if FolderShortcut and IsWindowsXP then
      WideFilename := StringToOleStr(PathChangeExt(Filename, ''))
    else
      WideFilename := StringToOleStr(Filename);
    OleResult := PF.Save(WideFilename, True);
    if OleResult <> S_OK then
      RaiseOleError('IPersistFile::Save', OleResult);

    Result := GetResultingFilename(PF, Filename);
  finally
    if Assigned(WideFilename) then
      SysFreeString(WideFilename);
    if Assigned(PF) then
      PF.Release;
    SL.Release;
  end;
{$ELSE}
var
  OleResult: HRESULT;
  Obj: IUnknown;
  SL: IShellLink;
  PF: IPersistFile;
  WideFilename: WideString;
begin
  if FolderShortcut then begin
    try
      Obj := CreateComObject(CLSID_FolderShortcut);
    except
      { Folder shortcuts aren't supported prior to Windows 2000/Me. Fall back
        to creating a normal shell link. }
      Obj := nil;
    end;
  end;
  if Obj = nil then begin
    FolderShortcut := False;
    Obj := CreateComObject(CLSID_ShellLink);
  end;
  SL := Obj as IShellLink;
  SL.SetPath(PChar(ShortcutTo));
  SL.SetArguments(PChar(Parameters));
  if WorkingDir <> '' then
    SL.SetWorkingDirectory(PChar(WorkingDir));
  if IconFilename <> '' then
    SL.SetIconLocation(PChar(IconFilename), IconIndex);
  SL.SetShowCmd(ShowCmd);
  if Description <> '' then
    SL.SetDescription(PChar(Description));
  if HotKey <> 0 then
    SL.SetHotKey(HotKey);

  PF := SL as IPersistFile;
  { When creating a folder shortcut on 2000/Me, IPersistFile::Save will strip
    off everything past the last '.' in the filename, so we keep the .lnk
    extension on to give it something harmless to strip off. XP doesn't do
    that, so we must remove the .lnk extension ourself. }
  if FolderShortcut and IsWindowsXP then
    WideFilename := PathChangeExt(Filename, '')
  else
    WideFilename := Filename;
  OleResult := PF.Save(PWideChar(WideFilename), True);
  if OleResult <> S_OK then
    RaiseOleError('IPersistFile::Save', OleResult);

  Result := GetResultingFilename(PF, Filename);
  { Delphi 3 automatically releases COM objects when they go out of scope }
{$ENDIF}
end;

procedure RegisterTypeLibrary(const Filename: String);
{$IFNDEF Delphi3OrHigher}
var
  WideFilename: PWideChar;
  OleResult: HRESULT;
  TypeLib: ITypeLib;
  DocName: PWideChar;
  DocNameStr: String;
begin
  WideFilename := StringToOleStr(PathExpand(Filename));
  TypeLib := nil;
  DocName := nil;
  try
    OleResult := LoadTypeLib(WideFilename, TypeLib);
    if FAILED(OleResult) then
      RaiseOleError('LoadTypeLib', OleResult);
    OleResult := TypeLib.GetDocumentation(-1, nil, nil, nil, @DocName);
    if FAILED(OleResult) then
      RaiseOleError('ITypeLib::GetDocumentation', OleResult);
    if Assigned(DocName) then begin
      DocNameStr := PathExtractPath(OleStrToString(DocName));
      SysFreeString(DocName);
      DocName := nil;
      DocName := StringToOleStr(DocNameStr);
    end;
    OleResult := RegisterTypeLib(TypeLib, WideFilename, DocName);
    if FAILED(OleResult) then
      RaiseOleError('RegisterTypeLib', OleResult);
  finally
    if Assigned(DocName) then
      SysFreeString(DocName);
    if Assigned(TypeLib) then
      TypeLib.Release;
    SysFreeString(WideFilename);
  end;
end;
{$ELSE}
var
  WideFilename: WideString;
  OleResult: HRESULT;
  TypeLib: ITypeLib;
  DocName: WideString;
begin
  WideFilename := PathExpand(Filename);
  OleResult := LoadTypeLib(PWideChar(WideFilename), TypeLib);
  if FAILED(OleResult) then
    RaiseOleError('LoadTypeLib', OleResult);
  OleResult := TypeLib.GetDocumentation(-1, nil, nil, nil, @DocName);
  if FAILED(OleResult) then
    RaiseOleError('ITypeLib::GetDocumentation', OleResult);
  if DocName <> '' then
    DocName := PathExtractPath(DocName);
  OleResult := RegisterTypeLib(TypeLib, PWideChar(WideFilename), Pointer(DocName));
  { ^ use Pointer cast instead of PWideChar so that it passes 'nil' if DocName is empty }
  if FAILED(OleResult) then
    RaiseOleError('RegisterTypeLib', OleResult);
end;
{$ENDIF}

function UnregisterTypeLibrary(const Filename: String): Boolean;
type
  TUnRegTlbProc = function(const libID: TGUID; wVerMajor, wVerMinor: Word;
    lcid: TLCID; syskind: TSysKind): HResult; stdcall;
{$IFNDEF Delphi3OrHigher}
var
  WideFilename: PWideChar;
  TypeLib: ITypeLib;
  OleAutLib: THandle;
  UnRegTlbProc: TUnRegTlbProc;
  LibAttr: PTLibAttr;
begin
  Result := False;
  WideFilename := nil;
  TypeLib := nil;
  LibAttr := nil;
  try
    { Dynamically import UnRegisterTypeLib since older OLEAUT32.DLL versions
      don't have this function }
    OleAutLib := GetModuleHandle('OLEAUT32.DLL');
    if OleAutLib = 0 then
      Exit;
    @UnRegTlbProc := GetProcAddress(OleAutLib, 'UnRegisterTypeLib');;
    if @UnRegTlbProc = nil then
      Exit;
    WideFilename := StringToOleStr(PathExpand(Filename));
    if FAILED(LoadTypeLib(WideFilename, TypeLib)) then
      Exit;
    if FAILED(TypeLib.GetLibAttr(LibAttr)) then
      Exit;
    with LibAttr^ do
      if FAILED(UnRegTlbProc(Guid, wMajorVerNum, wMinorVerNum, LCID, SysKind)) then
        Exit;
  finally
    if Assigned(TypeLib) then begin
      if Assigned(LibAttr) then
        TypeLib.ReleaseTLibAttr(LibAttr);
      TypeLib.Release;
    end;
    if Assigned(WideFilename) then
      SysFreeString(WideFilename);
  end;
  Result := True;
end;
{$ELSE}
var
  WideFilename: WideString;
  TypeLib: ITypeLib;
  OleAutLib: THandle;
  UnRegTlbProc: TUnRegTlbProc;
  LibAttr: PTLibAttr;
begin
  Result := False;
  { Dynamically import UnRegisterTypeLib since older OLEAUT32.DLL versions
    don't have this function }
  OleAutLib := GetModuleHandle('OLEAUT32.DLL');
  if OleAutLib = 0 then
    Exit;
  @UnRegTlbProc := GetProcAddress(OleAutLib, 'UnRegisterTypeLib');;
  if @UnRegTlbProc = nil then
    Exit;
  WideFilename := PathExpand(Filename);
  if FAILED(LoadTypeLib(PWideChar(WideFilename), TypeLib)) then
    Exit;
  if FAILED(TypeLib.GetLibAttr(LibAttr)) then
    Exit;
  try
    with LibAttr^ do
      if FAILED(UnRegTlbProc(Guid, wMajorVerNum, wMinorVerNum, LCID, SysKind)) then
        Exit;
  finally
    TypeLib.ReleaseTLibAttr(LibAttr);
  end;
  Result := True;
end;
{$ENDIF}

procedure InitOle;
var
  OleResult: HRESULT;
begin
  OleResult := CoInitialize(nil);
  if FAILED(OleResult) then
    raise Exception.CreateFmt('CoInitialize failed (0x%.8x)', [OleResult]);
    { ^ doesn't use a SetupMessage since messages probably aren't loaded
      during 'initialization' section below, which calls this procedure }
end;

initialization
  InitOle;
finalization
  CoUninitialize;
end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -