Inno Setup—調用dll外部庫實現一鍵安裝


該文只是對調用dll來實現一鍵安裝的概述,沒有具體說明dll內部怎樣實現!僅供參考!

 

1、c++寫的dll中的函數及dll文件截圖

 

extern "C"
{
//描述:安裝服務初始化
//參數:pszFileDir插件解壓的所在目錄
bool __stdcall SetupInit(char *pszFileDir);

//描述:顯示安裝操作界面
void __stdcall SetupShowMainWnd();

//描述:關閉安裝操作界面
void __stdcall SetupCloseMainwWnd();

//描述:等待用戶選擇是否安裝
//返回值:1:表示進入安裝、2:表示退出安裝
int __stdcall SetupWaitUserAction();

//描述:獲取安裝用戶選擇的路徑
//返回值:返回拷貝的字符串長度
char *__stdcall SetupGetInstallPath();

//描述:設置當前安裝的進度
//參數:nCurProgress 當前安裝的進度值
//參數:nMaxProgress 安裝進度最大值
//返回值:無
void __stdcall SetupSetProgress(int nCurProgress,int nMaxProgress);

//描述:等待用戶點擊安裝完成
void __stdcall SetupWaitCompleted();

//顯示一個錯誤提示模態對話框
//參數:psztipTxt 提示的文本
bool __stdcall ShowTipWnd(char *psztipTxt);

//描述:安裝服務反初始化
void __stdcall SetupUninit();

//描述:隱藏當前線程所有窗口
void __stdcall HideCurThreadAllWnd();

void __stdcall DeleteFileEx(char *pszFilePath);
};

  

2、申明函數 

[Code]
function SetupInit(pszFileDir: PAnsiChar):Boolean;
external 'SetupInit@files:InstallPlug.dll,DuiLib.dll,Lang.xml,skin.zip stdcall setuponly delayload loadwithalteredsearchpath';

procedure SetupShowMainWnd();
external 'SetupShowMainWnd@files:InstallPlug.dll,DuiLib.dll,Lang.xml,skin.zip stdcall setuponly delayload loadwithalteredsearchpath';

procedure SetupCloseMainwWnd();
external 'SetupCloseMainwWnd@files:InstallPlug.dll,DuiLib.dll,Lang.xml,skin.zip stdcall setuponly delayload loadwithalteredsearchpath';

function SetupWaitUserAction():Integer;
external 'SetupWaitUserAction@files:InstallPlug.dll,DuiLib.dll,Lang.xml,skin.zip stdcall setuponly delayload loadwithalteredsearchpath';

function SetupGetInstallPath():PAnsiChar;
external 'SetupGetInstallPath@files:InstallPlug.dll,DuiLib.dll,Lang.xml,skin.zip stdcall setuponly delayload loadwithalteredsearchpath';

procedure SetupSetProgress(nCurProgress,nMaxProgress:Integer);
external 'SetupSetProgress@files:InstallPlug.dll,DuiLib.dll,Lang.xml,skin.zip stdcall setuponly delayload loadwithalteredsearchpath';

procedure SetupWaitCompleted();
external 'SetupWaitCompleted@files:InstallPlug.dll,DuiLib.dll,Lang.xml,skin.zip stdcall setuponly delayload loadwithalteredsearchpath';

procedure SetupUninit();
external 'SetupUninit@files:InstallPlug.dll,DuiLib.dll,Lang.xml,skin.zip stdcall setuponly delayload loadwithalteredsearchpath';

function ShowTipWnd(psztipTxt:PAnsiChar):Boolean;
external 'ShowTipWnd@files:InstallPlug.dll,DuiLib.dll,Lang.xml,skin.zip stdcall setuponly delayload loadwithalteredsearchpath';

procedure HideCurThreadAllWnd();
external 'HideCurThreadAllWnd@files:InstallPlug.dll,DuiLib.dll,Lang.xml,skin.zip stdcall setuponly delayload loadwithalteredsearchpath';

procedure DeleteFileEx(pszFilePath:PAnsiChar);
external 'DeleteFileEx@files:InstallPlug.dll,DuiLib.dll,Lang.xml,skin.zip stdcall setuponly delayload loadwithalteredsearchpath';

//全局變量
var
RootDestFolder,installparam:string;

概述:

Pascal腳本能調用外部dll(標准Win32 API或者各程序員編寫的dll)中的函數,在調用外部dll中的函數前,需要聲明所調用的函數原型,使用external聲明dll文件,對於一個Pascal描述的函數原型,

例如 function A(B: Integer): Integer;可以有三種方式調用: 

方法一: 
function A(B: Integer): Integer; 
external '<  dll中函數名稱>  >@<  dll文件路徑  >'; 

方法二: 
function A(B: Integer): Integer; 
external '<  dll中函數名稱>  >@<  dll文件路徑  > <調用約定>'; 

方法三: 
function A(B: Integer): Integer; 
external '<dll中函數名稱>@<dll文件路徑> <調用約定> <選項>'; 


第一種方法最簡單,這是Pascal腳本的默認調用方法,調用約定為stdcall,絕大部分的調用都是采用這種方式,當然也可以使用其他的調用約定:cdecl、pascal和register

  

另外:

函數有返回值的,用function;無返回值的,用procedure 

 

 3、初始安裝

//初始安裝
function InitializeSetup(): Boolean;
var
RetValue,RetValue1,RetValue2,RetValue3,RetValue4,version0,IsRunning,installorexit:Integer; 
mypath,msgboxinfo,tmpintallpath,testpath:string;
isintallpath: Boolean; 
begin
installparam := GetMyParam('/VERYSILENT'); //判斷是否是靜默安裝命令
RootDestFolder:='';
//安裝服務初始化
setlength(tmpintallpath,1024);
tmpintallpath := ExpandConstant('{tmp}\');	
if SetupInit(tmpintallpath) then
begin  
while IsRunning=0 do 
begin 
  Result :=true; //安裝程序繼續	  
  //**********安裝之前判斷ErrorReport.exe是否正在運行**************** 
  msgboxinfo :='';   Exec('cmd.exe', '/C tasklist|findstr /i "ErrorReport.exe"', '', SW_HIDE,ewWaitUntilTerminated, RetValue3); //0為進程在運行,1為進程沒有運行   
  if RetValue3=0 then msgboxinfo := msgboxinfo+ 'ErrorReport.exe{n}';  
  if ShowTipWnd(ExpandConstant('{cm:MyMsgboxinfoInstall}')+msgboxinfo+ExpandConstant('{cm:MyMsgboxinfoInstall2}')) then    
  begin  
    IsRunning :=0;	    
  end else     
  begin 	  
    IsRunning :=1;		  
    Result :=false; //安裝程序退出    
  end; 	

  //**********運行一鍵安裝的界面****************  
  HideCurThreadAllWnd(); //隱藏當前線程所有窗口,為了解決安裝時任務欄顯示inno原來的安裝窗口以及dll寫的一個安裝窗口,兩個安裝窗口同時存在的情況
  
  //installparam為空則表示沒有靜默安裝的命令,表示本次安裝是非靜默安裝,則需要顯示一鍵安裝的界面,按照安裝步驟一步步進行安裝
  if  installparam='' then 
  begin  
	SetupShowMainWnd(); //顯示安裝操作界面
	installorexit := SetupWaitUserAction();//等待用戶選擇是否安裝,返回值:1:表示進入安裝、2:表示退出安裝
	if installorexit=1 then 
	begin
	  RootDestFolder:=SetupGetInstallPath(); //獲取安裝用戶選擇的路徑
	end else
	begin
	  SetupCloseMainwWnd(); //關閉安裝操作界面				
	  Result :=false; 
	end 
  //本次安裝是靜默安裝,不顯示任何安裝界面,直接獲取安裝路徑
  end else
	RootDestFolder:=SetupGetInstallPath();
  //******************************** 			
 end;
end 
end;

  

4、隱藏inno原來的安裝界面

procedure InitializeWizard();
begin
//不顯示邊框,這樣就能達到不會閃兩下了
WizardForm.BorderStyle:=bsNone;
end;


//不顯示一些特定的安裝界面 
function ShouldSkipPage(PageID: Integer): Boolean;
begin 
    Result := True
end;

//改變頁面時隱藏界面窗口
procedure CurPageChanged(CurPageID: Integer);
var 
indexpageid3:Integer;
begin
	//因為安裝過程界面隱藏不了,所以設置窗口寬高為0
	WizardForm.ClientWidth := ScaleX(0);
	WizardForm.ClientHeight := ScaleY(0);
 
	//在InnoSetup中,我們很容易用 function ShouldSkipPage(CurPage: Integer): Boolean; 來跳過一些頁面,但是Welcome Page是無法用這個函數來跳過的。如果一定要實現這樣的功能,可以用消息來模擬鼠標按鍵
	if CurPageID = wpWelcome then
	WizardForm.NextButton.OnClick(WizardForm);

	if CurPageID >= wpInstalling then
            WizardForm.Visible := False
        else
            WizardForm.Visible := True; 	
end;    

   

  

5、顯示安裝進度

procedure CurInstallProgressChanged(CurProgress, MaxProgress: Integer);
begin 
	if  installparam='' then 
	SetupSetProgress(CurProgress,MaxProgress);
end;

  

6、程序安裝之前和安裝之后執行操作

procedure CurStepChanged(CurStep: TSetupStep);
var
	IniPath : string;
begin
  if (CurStep=ssInstall) then  begin
    SetLanCode();
  end;
  if (CurStep=ssPostInstall ) then begin
   	if  installparam='' then SetupWaitCompleted();//非靜默安裝才需要執行
  end;
end;

 

7、反初始化

//反初始化
procedure DeinitializeSetup;
begin
   SetupUninit(); 	
end;

 

8、其他函數

//獲取安裝參數
function GetMyParam(PName:String):String;  
var  
  CmdLine : String;  
  CmdLineLen : Integer;  
  i : Integer;  
begin  
    CmdLineLen:=ParamCount();  
    for i:=0 to CmdLineLen do  
    begin  
    CmdLine:=ParamStr(i);  
    if CmdLine= PName then  
      begin  
          //CmdLine:=ParamStr(i+1);  
          Result := CmdLine;  
          Exit;  
      end;  
    end;   
end;

 

//判斷是否靜默安裝
function IsSilentInstall():Boolean;
begin
  Result := not (installparam ='') ;//installparam 在InitializeSetup中獲取到值了,這里只是進行判斷
end;

  

//返回真正的安裝路徑
function MyDestDir(SubDir:String):String;
begin
  if SubDir = '' then
    Result := RootDestFolder
  else
    Result := RootDestFolder + '\'+ SubDir;
end; 

  

8、定制安裝路徑  

因為我的程序修改了安裝界面,所以我的界面中提供了更改安裝路徑的方法。
用戶修改后的路徑會被傳回inno setup腳本,腳本中需要做的事情如下:
1,寫一個函數,來返回新的安裝路徑,如:
function MyDestDir(SubDir:String):String;
begin
  if SubDir = '' then
    Result := RootDestFolder
  else
    Result := RootDestFolder + '\'+ SubDir;
end; 
2,把原來使用{app}的地方都改成:{code:MyDestDir},安裝腳本自己能夠調用MyDestDir並得到正確的路徑。如:
Source: "test.xml"; DestDir: {code:MyDestDir}; 
Source: "\res\ReloadHigh\*"; DestDir: {code:MyDestDir|res\ReloadHigh}
最后記得加上:UninstallFilesDir={code:MyDestDir}, 否則卸載程序會被放到{app}.
 
例如:
[Setup]
UninstallDisplayIcon={code:MyDestDir|{#MyRegProductName}\XXX.exe}
UninstallFilesDir={code:MyDestDir}

[Files]
Source: "{#ComonBinDir}\XXX\YYY\*"; DestDir: {code:MyDestDir|{#MyRegProductName}}; Flags: ignoreversion recursesubdirs createallsubdirs  
Source: "{#ComonBinDir}\XXX\YYY\FMRun64.dll";DestDir: {code:MyDestDir|{#MyRegProductName}}; Flags: ignoreversion; Check:IsWin64 

[Icons]
Name: "{group}{#MyAppVision}\{cm:MyAppName}{#MyAppVision}"; Filename: {code:MyDestDir|{#MyRegProductName}\{#MyAppExeName}}
Name: "{group}{#MyAppVision}\{cm:MyScreenAppName}"; Filename: {code:MyDestDir|{#MyRegScreenProductName}\Screen.exe}
Name: "{group}{#MyAppVision}\{cm:UninstallProgram,{cm:MyAppName}}{#MyAppVision}"; Filename: "{uninstallexe}" 
Name: "{commondesktop}\{cm:MyAppName}{#MyAppVision}"; Filename: {code:MyDestDir|{#MyRegProductName}\{#MyAppExeName}}; Tasks: desktopicon

  

注意:
如果在定制后的DLL中修改安裝路徑,可以讓inno setup把原來的路徑以TCHAR*的形式傳給DLL,DLL直接修改。
但因為PASCAL的String類型並非是C語言的0結尾字符串,它會記錄字符串的真實長度,所以被C語言修改后的String不能直接使用。因為長度不一定相同(實際情況是如果長度沒變,就是正確的,如果長度有變化,程序安裝路徑中的文件名就不見了,安裝不了)。
所以在從DLL返回后,需要使用Length函數重新給String設置正確的長度。
 
9、最終實現效果
 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM