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、最终实现效果
 

 

 

posted @ 2016-08-04 15:40  kiss.fancy  阅读(9644)  评论(8编辑  收藏  举报