C# · 12月 20, 2021

在 C# 中执行 msi 安装

msiexec.exe /qn

[DllImport(,CharSet = MsiSetInternalUI( dwUILevel,IntPtr phWnd);

NativeMethods.MsiSetInternalUI(,IntPtr.Zero)

[DllImport(,CharSet = MsiInstallUIHandler MsiSetExternalUI([MarshalAs(UnmanagedType.FunctionPtr)] MsiInstallUIHandler puiHandler,NativeMethods.InstallLogMode dwMessageFilter,IntPtr pvContext);

[DllImport(,CharSet = MsiInstallProduct([MarshalAs(UnmanagedType.LPWStr)] szPackagePath,[MarshalAs(UnmanagedType.LPWStr)] szCommandLine);

[DllImport(,CharSet = MsiEnableLog(GcMsiUtil.NativeMethods.InstallLogMode dwLogMode,[MarshalAs(UnmanagedType.LPWStr)] szLogFile, dwLogAttributes);

MyInstaller _installer = BackgroundWorker _installerBGWorker = _installer </span>= <span style=”color: #0000ff”&gt;new</span><span style=”color: #000000″&gt; MyInstaller(); _installerBGWorker.WorkerReportsProgress </span>= <span style=”color: #0000ff”&gt;true</span><span style=”color: #000000″&gt;; _installerBGWorker.WorkerSupportsCancellation </span>= <span style=”color: #0000ff”&gt;true</span><span style=”color: #000000″&gt;; _installerBGWorker.DoWork </span>+=<span style=”color: #000000″&gt; _installerBGWorker_DoWork; _installerBGWorker.RunWorkerCompleted </span>+=<span style=”color: #000000″&gt; _installerBGWorker_RunWorkerCompleted; _installerBGWorker.ProgressChanged </span>+=<span style=”color: #000000″&gt; _installerBGWorker_ProgressChanged; </span><span style=”color: #0000ff”&gt;this</span>.Shown +=<span style=”color: #000000″&gt; InstallProcessForm_Shown;}</span><span style=”color: #0000ff”&gt;private</span> <span style=”color: #0000ff”&gt;void</span> InstallProcessForm_Shown(<span style=”color: #0000ff”&gt;object</span><span style=”color: #000000″&gt; sender,EventArgs e){ </span><span style=”color: #008000″&gt;//</span><span style=”color: #008000″&gt; 当窗口打开后就开始<a href=”https://www.jb51.cc/tag/houtai/” target=”_blank” class=”keywords”>后台</a>的安装</span>

<span style=”color: #000000″> _installerBGWorker.RunWorkerAsync();
}

</span><span style=”color: #0000ff”&gt;private</span> <span style=”color: #0000ff”&gt;void</span> _installerBGWorker_ProgressChanged(<span style=”color: #0000ff”&gt;object</span><span style=”color: #000000″&gt; sender,ProgressChangedEventArgs e){ </span><span style=”color: #008000″&gt;//</span><span style=”color: #008000″&gt; 消息通过 e.UserState 传回,并通过label<a href=”https://www.jb51.cc/tag/xianshi/” target=”_blank” class=”keywords”>显示</a>在窗口上</span> <span style=”color: #0000ff”&gt;string</span> message =<span style=”color: #000000″&gt; e.UserState.ToString(); </span><span style=”color: #0000ff”&gt;this</span>.label1.Text =<span style=”color: #000000″&gt; message; </span><span style=”color: #0000ff”&gt;if</span> (message == <span style=”color: #800000″&gt;”</span><span style=”color: #800000″&gt;正在取消安装 …</span><span style=”color: #800000″&gt;”</span><span style=”color: #000000″&gt;) { </span><span style=”color: #0000ff”&gt;this</span>.CancelButton.Enabled = <span style=”color: #0000ff”&gt;false</span><span style=”color: #000000″&gt;; }}</span><span style=”color: #0000ff”&gt;private</span> <span style=”color: #0000ff”&gt;void</span> _installerBGWorker_RunWorkerCompleted(<span style=”color: #0000ff”&gt;object</span><span style=”color: #000000″&gt; sender,RunWorkerCompletedEventArgs e){ </span><span style=”color: #008000″&gt;//</span><span style=”color: #008000″&gt; 安装过程结束</span>

<span style=”color: #000000″> }

</span><span style=”color: #0000ff”&gt;private</span> <span style=”color: #0000ff”&gt;void</span> _installerBGWorker_DoWork(<span style=”color: #0000ff”&gt;object</span><span style=”color: #000000″&gt; sender,DoWorkEventArgs e){ BackgroundWorker bgWorker </span>= sender <span style=”color: #0000ff”&gt;as</span><span style=”color: #000000″&gt; BackgroundWorker; </span><span style=”color: #008000″&gt;//</span><span style=”color: #008000″&gt; 开始执行安装<a href=”https://www.jb51.cc/tag/fangfa/” target=”_blank” class=”keywords”>方法</a></span> _installer = <span style=”color: #0000ff”&gt;new</span><span style=”color: #000000″&gt; MyInstaller(); </span><span style=”color: #0000ff”&gt;string</span> msiFilePath = <span style=”color: #800000″&gt;”</span><span style=”color: #800000″&gt;xxx.msi</span><span style=”color: #800000″&gt;”</span>; <span style=”color: #008000″&gt;//</span><span style=”color: #008000″&gt; msi file path</span>

<span style=”color: #000000″> _installer.Install(bgWorker,msiFilePath);
}

</span><span style=”color: #0000ff”&gt;private</span> <span style=”color: #0000ff”&gt;void</span> CancelButton_Click(<span style=”color: #0000ff”&gt;object</span><span style=”color: #000000″&gt; sender,EventArgs e){ _installer.Canceled </span>= <span style=”color: #0000ff”&gt;true</span><span style=”color: #000000″&gt;; _installerBGWorker.CancelAsync();}

}
MyInstaller.cs
<span style=”color: #0000ff”>internal <span style=”color: #0000ff”>class<span style=”color: #000000″> MyInstaller
{
<span style=”color: #0000ff”>private BackgroundWorker _bgWorker = <span style=”color: #0000ff”>null<span style=”color: #000000″>;

</span><span style=”color: #0000ff”&gt;public</span> <span style=”color: #0000ff”&gt;bool</span> Canceled { <span style=”color: #0000ff”&gt;get</span>; <span style=”color: #0000ff”&gt;set</span><span style=”color: #000000″&gt;; }</span><span style=”color: #0000ff”&gt;public</span> <span style=”color: #0000ff”&gt;void</span> Install(BackgroundWorker bgWorker,<span style=”color: #0000ff”&gt;string</span><span style=”color: #000000″&gt; msiFileName){ _bgWorker </span>=<span style=”color: #000000″&gt; bgWorker; NativeMethods.MyMsiInstallUIHandler oldHandler </span>= <span style=”color: #0000ff”&gt;null</span><span style=”color: #000000″&gt;; </span><span style=”color: #0000ff”&gt;try</span><span style=”color: #000000″&gt; { </span><span style=”color: #0000ff”&gt;string</span> logPath = <span style=”color: #800000″&gt;”</span><span style=”color: #800000″&gt;test.log</span><span style=”color: #800000″&gt;”</span><span style=”color: #000000″&gt;; NativeMethods.MsiEnableLog(NativeMethods.LogMode.Verbose,logPath,</span><span style=”color: #800080″&gt;0u</span><span style=”color: #000000″&gt;); NativeMethods.MsiSetInternalUI(</span><span style=”color: #800080″&gt;2</span><span style=”color: #000000″&gt;,IntPtr.Zero); oldHandler </span>= NativeMethods.MsiSetExternalUI(<span style=”color: #0000ff”&gt;new</span><span style=”color: #000000″&gt; NativeMethods.MyMsiInstallUIHandler(MsiProgressHandler),NativeMethods.LogMode.ExternalUI,IntPtr.Zero); </span><span style=”color: #0000ff”&gt;string</span> param = <span style=”color: #800000″&gt;”</span><span style=”color: #800000″&gt;ACTION=INSTALL</span><span style=”color: #800000″&gt;”</span><span style=”color: #000000″&gt;; _bgWorker.ReportProgress(</span><span style=”color: #800080″&gt;0</span>,<span style=”color: #800000″&gt;”</span><span style=”color: #800000″&gt;正在安装 xxx …</span><span style=”color: #800000″&gt;”</span><span style=”color: #000000″&gt;); NativeMethods.MsiInstallProduct(msiFileName,param); } </span><span style=”color: #0000ff”&gt;catch</span><span style=”color: #000000″&gt;(Exception e) { </span><span style=”color: #008000″&gt;//</span><span style=”color: #008000″&gt; todo</span>

<span style=”color: #000000″> }
<span style=”color: #0000ff”>finally<span style=”color: #000000″>
{
<span style=”color: #008000″>//<span style=”color: #008000″> 一定要把默认的handler设回去。
<span style=”color: #0000ff”>if(oldHandler != <span style=”color: #0000ff”>null<span style=”color: #000000″>)
{
NativeMethods.MsiSetExternalUI(oldHandler,NativeMethods.LogMode.None,IntPtr.Zero);
}
}
}

</span><span style=”color: #008000″&gt;//</span><span style=”color: #008000″&gt;最重要的就是这个<a href=”https://www.jb51.cc/tag/fangfa/” target=”_blank” class=”keywords”>方法</a>了,这里仅演示了如何cancel<a href=”https://www.jb51.cc/tag/yige/” target=”_blank” class=”keywords”>一个</a>安装,更多详情请参考MSDN文档</span><span style=”color: #0000ff”&gt;private</span> <span style=”color: #0000ff”&gt;int</span> MsiProgressHandler(IntPtr context,<span style=”color: #0000ff”&gt;int</span> messageType,<span style=”color: #0000ff”&gt;string</span><span style=”color: #000000″&gt; message){ </span><span style=”color: #0000ff”&gt;if</span> (<span style=”color: #0000ff”&gt;this</span><span style=”color: #000000″&gt;.Canceled) { </span><span style=”color: #0000ff”&gt;if</span> (_bgWorker != <span style=”color: #0000ff”&gt;null</span><span style=”color: #000000″&gt;) { _bgWorker.ReportProgress(</span><span style=”color: #800080″&gt;0</span>,<span style=”color: #800000″&gt;”</span><span style=”color: #800000″&gt;正在取消安装 …</span><span style=”color: #800000″&gt;”</span><span style=”color: #000000″&gt;); } </span><span style=”color: #008000″&gt;//</span><span style=”color: #008000″&gt; 这个返回值会告诉msi,cancel当前的安装</span> <span style=”color: #0000ff”&gt;return</span> <span style=”color: #800080″&gt;2</span><span style=”color: #000000″&gt;; } </span><span style=”color: #0000ff”&gt;return</span> <span style=”color: #800080″&gt;1</span><span style=”color: #000000″&gt;;}

}

<span style=”color: #0000ff”>internal <span style=”color: #0000ff”>static <span style=”color: #0000ff”>class<span style=”color: #000000″> NativeMethods
{
[DllImport(<span style=”color: #800000″>”<span style=”color: #800000″>msi.dll<span style=”color: #800000″>”,CharSet =<span style=”color: #000000″> CharSet.Auto)]
<span style=”color: #0000ff”>internal <span style=”color: #0000ff”>static <span style=”color: #0000ff”>extern <span style=”color: #0000ff”>int MsiSetInternalUI(<span style=”color: #0000ff”>int<span style=”color: #000000″> dwUILevel,IntPtr phWnd);

[DllImport(</span><span style=”color: #800000″&gt;”</span><span style=”color: #800000″&gt;msi.dll</span><span style=”color: #800000″&gt;”</span>,CharSet =<span style=”color: #000000″&gt; CharSet.Auto)]</span><span style=”color: #0000ff”&gt;internal</span> <span style=”color: #0000ff”&gt;static</span> <span style=”color: #0000ff”&gt;extern</span><span style=”color: #000000″&gt; MyMsiInstallUIHandler MsiSetExternalUI([MarshalAs(UnmanagedType.FunctionPtr)] MyMsiInstallUIHandler puiHandler,NativeMethods.LogMode dwMessageFilter,IntPtr pvContext);[DllImport(</span><span style=”color: #800000″&gt;”</span><span style=”color: #800000″&gt;msi.dll</span><span style=”color: #800000″&gt;”</span>,CharSet =<span style=”color: #000000″&gt; CharSet.Auto)]</span><span style=”color: #0000ff”&gt;internal</span> <span style=”color: #0000ff”&gt;static</span> <span style=”color: #0000ff”&gt;extern</span> <span style=”color: #0000ff”&gt;uint</span> MsiInstallProduct([MarshalAs(UnmanagedType.LPWStr)] <span style=”color: #0000ff”&gt;string</span> szPackagePath,[MarshalAs(UnmanagedType.LPWStr)] <span style=”color: #0000ff”&gt;string</span><span style=”color: #000000″&gt; szCommandLine);[DllImport(</span><span style=”color: #800000″&gt;”</span><span style=”color: #800000″&gt;msi.dll</span><span style=”color: #800000″&gt;”</span>,CharSet =<span style=”color: #000000″&gt; CharSet.Auto)]</span><span style=”color: #0000ff”&gt;internal</span> <span style=”color: #0000ff”&gt;static</span> <span style=”color: #0000ff”&gt;extern</span> <span style=”color: #0000ff”&gt;uint</span> MsiEnableLog(NativeMethods.LogMode dwLogMode,<span style=”color: #0000ff”&gt;uint</span><span style=”color: #000000″&gt; dwLogAttributes);</span><span style=”color: #0000ff”&gt;internal</span> <span style=”color: #0000ff”&gt;delegate</span> <span style=”color: #0000ff”&gt;int</span> MyMsiInstallUIHandler(IntPtr context,[MarshalAs(UnmanagedType.LPWStr)] <span style=”color: #0000ff”&gt;string</span><span style=”color: #000000″&gt; message);[Flags]</span><span style=”color: #0000ff”&gt;internal</span> <span style=”color: #0000ff”&gt;enum</span> LogMode : <span style=”color: #0000ff”&gt;uint</span><span style=”color: #000000″&gt;{ None </span>= <span style=”color: #800080″&gt;0u</span><span style=”color: #000000″&gt;,Verbose </span>= <span style=”color: #800080″&gt;4096u</span><span style=”color: #000000″&gt;,ExternalUI </span>= <span style=”color: #800080″&gt;20239u</span><span style=”color: #000000″&gt;}

}