Inno Setup指南 —— 教程索引

InnoSetup指南 —— 教程索引

鉴于VSCode都用inno setup打包了,个人就学习一下用inno做安装包的简易操作

用Inno做一个最简单的安装包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

[Setup]
AppName=HelloWorld
AppVersion=1.0.0.0
WizardStyle=modern
DefaultDirName={autopf}\HelloWorld
DefaultGroupName=HelloWorld
UninstallDisplayIcon={app}\HelloWorld.exe
Compression=lzma2
SolidCompression=yes
OutputDir=userdocs:Inno Setup Examples Output
OutputBaseFilename=HelloWorldSetup

[Files]
Source: "HelloWorld.exe"; DestDir: "{app}"

  • Inno Setup Compiler打开.iss文件,若安装时,关联了.iss文件,可以直接双击打开
  • 点击编译 Compile 按钮,HelloWorldSetup.exe安装包将生成到用户文档目录下的Inno Setup Examples Output目录中

Read More

Wix Toolset 本地化MSI中文安装包制作

Wix Toolset 本地化MSI中文安装包制作

本文针对Wix制作**中文安装包(.msi)**中的一些内容进行整理 —— 其他语言类似
本文采用Visual Studio构建安装包 —— 推荐,因为足够方便。
示例源码

设置项目Cultures属性

  • zh-CN添加到项目的Cultures属性中【可以添加多种语言支持,以分号 ; 分隔】。
    • 方式一:右键项目属性修改:
    • 方式二:直接修改.wixproj项目文件内容,添加如下代码:
1
2
3
4
5

<PropertyGroup>
<Cultures>zh-CN;</Cultures>
</PropertyGroup>

添加WixUIExtension.dll引用

Wix安装包中基本流程的本地化资源已经打包至WixUIExtension.dll,引用此文件,即可在安装流程中显示中文流程。

见官方代码:https://github.com/wixtoolset/wix3/blob/master/src/ext/UIExtension/wixlib/WixUI_zh-CN.wxl

修改ProductLanguage属性

此值设置与否,并不影响中文安装包打包,不过既然做中文包,就做的彻底一些。

ProductLanguage的默认值为1033,其为en-usLCID,将其值改为2052,即zh-cn

1
2
3
4
5
6
7
8
9

<Product Id="*"
Name="Jess.Sample.Setup.ChineseLocalization"
Language="2052"
Version="1.0.0.0"
Manufacturer="Test中文"
UpgradeCode="0045cd81-6128-4e08-b8c2-357327c5c9ba">
</Product>

设置PackageSummaryCodepage属性

MSI属性 详细信息显示中文

PackageSummaryCodepage属性设置为936

1
2
3
4
5
6

<Package InstallerVersion="200"
Compressed="yes"
SummaryCodepage="936"
InstallScope="perMachine" />

设置此属性的作用,是让MSI安装包的属性-详细信息显示中文。

如下图,若不配置SummaryCodepage作者信息显示不了中文:

当未配置SummaryCodepage时,作者信息显示 Test,而非 Test中文


奇葩史

WPF中登录窗口的跳转处理

WPF中登录窗口的跳转处理

在WPF应用设计中,常常需要在主窗口之前设置一个前置登录窗口,为此整理了一下可行的方案。
示例源码:Jess.Sample.LoginWindow

方案一:添加Program.cs,模仿Winform初始代码

不做整理,个人不推荐,既然用了WPF,就尽量不把Winform的东西引入进来。

方案二:在主窗体MainWindow的构造函数中处理登录操作

此方案相对局限,若单纯只有个登录操作,可以使用此法 —— 可依据需要调整InitializeComponent();的先后顺序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

public partial class MainWindow : Window
{
public MainWindow()
{
WindowLogin win = new WindowLogin();
if (!(win.ShowDialog() ?? false))
{
App.Current.Shutdown();
return;
}

InitializeComponent();
}
}

方案三:重写ApplicationOnStartup方法

注意事项:

  • OnStartup中关闭窗体,会导致进入不了主窗体,因此需要手动控制ShutdownMode【默认值:ShutdownMode.OnLastWindowClose
  • 不得在App构造函数中,进行UI显示操作,因为这会导致一些锁的释放,引发OnStartup提前触发【OnStartup是在Application的构造函数中异步调用的】

官方Window.cs源码的窗体关闭流程中有一段以下代码:

1
2
3
4
5
6
7

if (((App.Windows.Count == 0) && (App.ShutdownMode == ShutdownMode.OnLastWindowClose))
|| ((App.MainWindow == this) && (App.ShutdownMode == ShutdownMode.OnMainWindowClose)))
{
App.CriticalShutdown(0);
}

由此可见,默认情况下,在OnStartup中调用关闭窗体,会直接导致Shutdown的调用。


鉴于此,主要有以下修改方式【只要避免内部调用Shutdown即可】:

保证登录窗体关闭时,不会满足Shutdown调用条件

  • 全局自己手动控制Shutdown:使用ShutdownMode.OnExplicitShutdown,在需要退出应用时,调用App.Current.Shutdown();
  • 在登录窗体前后,切换ShutdownMode:登录前改为ShutdownMode.OnExplicitShutdown,窗体关闭后,恢复为ShutdownMode.OnLastWindowClose
  • 控制只有主窗体关闭时,才退出程序:指定MainWindow,手动启动MainWindow,不在依赖StartupUri

全局手动控制Shutdown

  • 设置ShutdownMode为OnExplicitShutdown;
  • 在需要退出应用的窗体中,重写OnClosed方法,手动调用App.Current.Shutdown()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

public partial class App : Application
{
public App()
{
this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
}

protected override void OnStartup(StartupEventArgs e)
{
WindowLogin win = new WindowLogin();
if (!(win.ShowDialog() ?? false))
{
App.Current.Shutdown();
return;
}

base.OnStartup(e);
}
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
App.Current.Shutdown();
}
}

窗体显示前后切换ShutdownMode

  • 直接在登录窗体前后设置ShutdownMode即可:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
this.ShutdownMode = ShutdownMode.OnExplicitShutdown;
WindowLogin win = new WindowLogin();
if (!(win.ShowDialog() ?? false))
{
this.Shutdown();
return;
}
this.ShutdownMode = ShutdownMode.OnLastWindowClose;

base.OnStartup(e);
}
}

指定App主窗体MainWindow

  • 删除App.xaml文件中是StartupUri属性设置。
  • 设置主窗体与程序关闭模式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

public partial class App : Application
{
public App()
{
this.MainWindow = new MainWindow();
this.ShutdownMode = ShutdownMode.OnMainWindowClose;
}

protected override void OnStartup(StartupEventArgs e)
{
WindowLogin win = new WindowLogin();
if (!(win.ShowDialog() ?? false))
{
this.Shutdown();
return;
}

base.OnStartup(e);

this.MainWindow.Show();
}
}

补充说明

在上面前两种的OnStartup的处理中,有个隐藏的问题,他们仍然会去创建MainWindow。如果想避免初始化MainWindow,有以下两种方式:

  • 在调用Shutdown之后调用Environment.Exit(0);,强制退出。
  • 重写ApplicationOnNavigating方法,设置事件参数的Cancel属性。
1
2
3
4
5
6
7

protected override void OnNavigating(NavigatingCancelEventArgs e)
{
e.Cancel = true;
base.OnNavigating(e);
}


掘:奇葩史