当前位置:  开发笔记 > 编程语言 > 正文

将WinForms表单嵌入到Inno安装向导中

如何解决《将WinForms表单嵌入到Inno安装向导中》经验,为你挑选了1个好方法。

我需要将一个WinForms表单(with BorderStyle = None)嵌入到Inno安装向导中并出现问题.

这是一个Inno安装脚本:

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));
    }
}

它工作但不如预期.设置加载后,它会自动调用EmbedConfiguratorFormconfigurator.dll和窗体显示但不进入设置向导页面.它显示在后面(见截图).那么我做错了什么?

在此输入图像描述



1> Alexey Kulik..:

解决了.

解决方案是从DLL返回新窗口(窗体)的句柄,并使用user32.SetParentWinAPI函数强制将窗体嵌入到向导中.这是一段代码.

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安装脚本:

[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 'SetParent@user32.dll 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的注意事项:
它使用UnmanagedExportsNuGet包(包含DLLExportAttribute).

关于Inno Setup脚本的注意事项:
InitializeWizard函数中我们只需创建新页面,但我们需要实现DLL调用CurPageChanged以确保我们的页面现在打开.


经过一些研究工作,我创建了一个小样本项目,解释了.Net和InnoSetup的双向整合

https://github.com/sharpcoder7/innoGlue.net

推荐阅读
Life一切安好
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有