我需要将WinForms表单(带有BorderStyle = None
)嵌入到Inno Setup Wizard中,并出现问题。
这是一个Inno Setup脚本:
procedure EmbedConfiguratorForm(parentWnd: HWND);
external 'EmbedConfiguratorForm@files:configurator.dll stdcall';
procedure InitializeWizard();
var
cfgPageHandle: HWND;
begin
cfgPageHandle := CreateCustomPage(wpSelectDir,
'Configuration',
ExpandConstant(description)).Surface.Handle;
EmbedConfiguratorForm(cfgPageHandle);
end;
这是一个C#代码:
class WizardWindow : IWin32Window
{
public WizardWindow(IntPtr handle)
{
Handle = handle;
}
public WizardWindow(int handle) : this(new IntPtr(handle))
{
}
public IntPtr Handle { get; private set; }
}
public static class MainClass
{
[DllExport("EmbedConfiguratorForm", CallingConvention.StdCall)]
public static void EmbedConfiguratorForm(int parentWnd)
{
// System.Diagnostics.Debugger.Launch();
ConfiguratorForm form = new ConfiguratorForm();
form.Show(new WizardWindow(parentWnd));
}
}
它有效,但未达到预期效果。安装程序加载后,它会自动EmbedConfiguratorForm
从调用configurator.dll
并显示表单,但不会进入安装向导页面。它显示在后面(请参见屏幕截图)。那我在做什么错?
解决了。
解决方案是从DLL返回新窗口(窗体)的句柄,并使用user32.SetParent
WinAPI函数强制将窗体嵌入到向导中。这里是一段代码。
C#:
namespace configurator
{
class WizardWindow : IWin32Window
{
public WizardWindow(IntPtr handle)
{
Handle = handle;
}
public WizardWindow(int handle) : this(new IntPtr(handle))
{
}
public IntPtr Handle { get; private set; }
}
public static class MainClass
{
private static ConfiguratorForm _configuratorForm;
[DllExport("EmbedConfiguratorForm", CallingConvention.StdCall)]
public static IntPtr EmbedConfiguratorForm(int parentWnd)
{
_configuratorForm = new ConfiguratorForm();
_configuratorForm.Show(new WizardWindow(parentWnd));
return _configuratorForm.Handle;
}
[DllExport("CloseConfiguratorForm", CallingConvention.StdCall)]
public static void CloseConfiguratorForm()
{
if (_configuratorForm != null)
{
_configuratorForm.Close();
_configuratorForm.Dispose();
_configuratorForm = null;
}
}
}
}
Inno Setup脚本:
[Code]
const
description = 'my page description';
var
configFile: string;
configuratorPage: TWizardPage;
function EmbedConfiguratorForm(parentWnd: HWND): HWND;
external 'EmbedConfiguratorForm@files:configurator.dll stdcall';
procedure CloseConfiguratorForm();
external 'CloseConfiguratorForm@files:configurator.dll stdcall';
function SetParent(hWndChild, hWndNewParent: HWND): HWND;
external '[email protected] stdcall';
procedure InitializeWizard();
begin
configuratorPage := CreateCustomPage(wpSelectDir,
'Title', 'Description');
end;
procedure ShowConfigurationStep();
var
cfgPageHandle: HWND;
cfgWinHandle: HWND;
begin
cfgPageHandle := configuratorPage.Surface.Handle;
cfgWinHandle := EmbedConfiguratorForm(cfgPageHandle);
SetParent(cfgWinHandle, cfgPageHandle);
end;
procedure CurPageChanged(CurPageId: Integer);
begin
if (CurPageId = configuratorPage.ID) then
begin
ShowConfigurationStep();
end else
begin
CloseConfiguratorForm(); // here we can make some optimization like checking previos page
end;
end;
procedure DeinitializeSetup();
begin
CloseConfiguratorForm();
end;
关于C#DLL的注意事项:
它使用UnmanagedExports
NuGet数据包(包含DLLExportAttribute
)。
关于Inno Setup脚本的注意事项:
在InitializeWizard
函数中,我们只需要创建新页面,但是需要实现DLL调用CurPageChanged
以确保立即打开我们的页面。
经过一些研究工作,我创建了一个小示例项目来说明.Net和InnoSetup的双向集成
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句