CoInitializeSecurity 在 Visual Studio 2017 年抛出 RPC_E_TOO_LATE
CoInitializeSecurity throws RPC_E_TOO_LATE in Visual Studio 2017
我正在尝试 运行 应用程序在启动时调用 CoInitializeSecurity
。这在 Visual Studio 2013 年有效,但在 Visual Studio 2017 年无效 - 我很好奇为什么会这样。
在 Visual Studio 2017 年启动时调用 CoInitializeSecurity 时,我得到一个 COMException
,错误代码 RPC_E_TOO_LATE (0x80010119)
,表明已经对 CoInitialize
进行了调用,这Visual Studio 2013 年不会发生。
我在 Visual Studio 2013 年启用 Visual Studio 托管进程时或在调用 CoInitializeSecurity
之前加载使用 COM 的程序集时看到过此行为。
加载的程序集在 Visual Studio 2013 和 2017 之间有所不同(进入 App
构造函数时拍摄的快照),差异突出显示:
2013:
'WPFTestVS2017.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\WPFTestVS2017\bin\Debug\WPFTestVS2017.exe'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Xaml\v4.0_4.0.0.0__b77a5c561934e089\System.Xaml.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll'.
2017:
'WPFTestVS2017.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\WPFTestVS2017\bin\Debug\WPFTestVS2017.exe'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Xaml\v4.0_4.0.0.0__b77a5c561934e089\System.Xaml.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\Program Files (x86)\Microsoft Visual Studio17\Enterprise\Common7\IDE\Remote Debugger\x64\Runtime\Microsoft.VisualStudio.Debugger.Runtime.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll'.
远程调试器让我产生了怀疑,因为它让我想起了 Visual Studio 托管进程。另一行不同的是 System.Core.dll
,它没有出现在 VS2013 的加载程序集中。
代码:
App.xaml
<Application x:Class="WPFTestVS2017.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
</Application>
App.xaml.cs
using System;
using System.Runtime.InteropServices;
using System.Windows;
namespace WPFTestVS2017
{
internal static class NativeMethods
{
private enum RpcAuthnLevel
{
Default = 0,
None = 1,
Connect = 2,
Call = 3,
Pkt = 4,
PktIntegrity = 5,
PktPrivacy = 6
}
private enum RpcImpLevel
{
Default = 0,
Anonymous = 1,
Identify = 2,
Impersonate = 3,
Delegate = 4
}
private enum EoAuthnCap
{
None = 0x0000,
MutualAuth = 0x0001,
StaticCloaking = 0x0020,
DynamicCloaking = 0x0040,
AnyAuthority = 0x0080,
MakeFullSIC = 0x0100,
Default = 0x0800,
SecureRefs = 0x0002,
AccessControl = 0x0004,
AppID = 0x0008,
Dynamic = 0x0010,
RequireFullSIC = 0x0200,
AutoImpersonate = 0x0400,
NoCustomMarshal = 0x2000,
DisableAAA = 0x1000
}
[DllImport("Ole32.dll",
ExactSpelling = true,
EntryPoint = "CoInitializeSecurity",
CallingConvention = CallingConvention.StdCall,
SetLastError = false,
PreserveSig = false)]
private static extern void CoInitializeSecurity(
IntPtr pVoid,
int cAuthSvc,
IntPtr asAuthSvc,
IntPtr pReserved1,
uint dwAuthnLevel,
uint dwImpLevel,
IntPtr pAuthList,
uint dwCapabilities,
IntPtr pReserved3);
public static void Initialize()
{
CoInitializeSecurity(IntPtr.Zero,
-1,
IntPtr.Zero,
IntPtr.Zero,
(uint)RpcAuthnLevel.PktPrivacy,
(uint)RpcImpLevel.Impersonate,
IntPtr.Zero,
(uint)EoAuthnCap.DynamicCloaking,
IntPtr.Zero);
}
}
public partial class App : Application
{
public App()
{
NativeMethods.Initialize();
}
}
}
MainWindow.xaml
<Window x:Class="WPFTestVS2017.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"/>
MainWindow.xaml.cs
using System.Windows;
namespace WPFTestVS2017
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
编辑:
我对App.xaml.cs
做了以下修改:
public App()
{
try
{
NativeMethods.Initialize();
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
消息框在 Visual Studio 2017 年调试时出现,但是,当 运行 在 Visual Studio.
之外运行相同的可执行文件时,它不会出现
您正在与 VS2017 中托管调试引擎的变化作斗争。它与您猜测的内容没有任何关系,我认为删除 Visual Studio Hosting Process 选项可能是相关的。瞎猜,这是一个黑盒子,如果没有微软调试团队的帮助,很难被攻破。
您有几种可能的解决方法,按实用性排序:
工具 > 选项 > 调试 > 常规,勾选 "Use Managed Compatibility Mode" 复选框。这将用旧的调试引擎替换新的调试引擎,最后在 VS2010 中使用。您会错过一些最新的调试器功能(新的 PDB 格式、return 值检查、64 位编辑+继续),这些功能几乎不会阻止您调试 WPF 应用程序。
如果不需要,您可以阻止函数抛出异常。将 [DllImport] 的 PreserveSig 属性 更改为 true,将 return 类型从 void 更改为 int。它仍然会失败,由负 return 值指示,但您可以继续调试其余代码。也许您想使用 return 值来设置您用来绕过棘手的 COM 代码的全局变量。
如果不需要,您可以延迟初始化调试引擎,直到 CoInitializeSecurity 调用之后。追加 System.Diagnostics.Debugger.Launch();
,用 #if DEBUG
包裹。现在您可以按 Ctrl+F5 开始调试,当您得到提示时,select VS 的 运行 实例作为所需的调试器。使用“调试”>“附加到进程”是类似的解决方法。
我终于设法找到了这个问题的解决方案 - 这个问题似乎起源于 STAThread
。
在 App.xaml
的属性中将构建操作从 ApplicationDefinition
切换到 Page
允许我们定义自己的 Main
方法,而不是使用 compiler-generated App.g.cs
.
中的一个
仍然使用问题中的NativeMethods
class作为参考:
internal static class NativeMethods
{
private enum RpcAuthnLevel
{
Default = 0,
None = 1,
Connect = 2,
Call = 3,
Pkt = 4,
PktIntegrity = 5,
PktPrivacy = 6
}
private enum RpcImpLevel
{
Default = 0,
Anonymous = 1,
Identify = 2,
Impersonate = 3,
Delegate = 4
}
private enum EoAuthnCap
{
None = 0x0000,
MutualAuth = 0x0001,
StaticCloaking = 0x0020,
DynamicCloaking = 0x0040,
AnyAuthority = 0x0080,
MakeFullSIC = 0x0100,
Default = 0x0800,
SecureRefs = 0x0002,
AccessControl = 0x0004,
AppID = 0x0008,
Dynamic = 0x0010,
RequireFullSIC = 0x0200,
AutoImpersonate = 0x0400,
NoCustomMarshal = 0x2000,
DisableAAA = 0x1000
}
[DllImport("Ole32.dll",
ExactSpelling = true,
EntryPoint = "CoInitializeSecurity",
CallingConvention = CallingConvention.StdCall,
SetLastError = false,
PreserveSig = false)]
private static extern void CoInitializeSecurity(
IntPtr pVoid,
int cAuthSvc,
IntPtr asAuthSvc,
IntPtr pReserved1,
uint dwAuthnLevel,
uint dwImpLevel,
IntPtr pAuthList,
uint dwCapabilities,
IntPtr pReserved3);
public static void Initialize()
{
CoInitializeSecurity(IntPtr.Zero,
-1,
IntPtr.Zero,
IntPtr.Zero,
(uint)RpcAuthnLevel.PktPrivacy,
(uint)RpcImpLevel.Impersonate,
IntPtr.Zero,
(uint)EoAuthnCap.DynamicCloaking,
IntPtr.Zero);
}
}
新的 Main
方法需要首先调用 CoInitializeSecurity
,如下所示:
internal static void Main()
{
NativeMethods.Initialize();
}
这里缺少一些东西,比如之前 运行 在 compiler-generated Main
中的逻辑。当我们调用 CoInitializeSecurity
时,我们现在需要 运行 具有 STA 线程模型的线程中的 App
构造函数,如下所示:
[DebuggerNonUserCode]
internal static void STAMain()
{
//This is what the compiler-generated Main method executes by default
App app = new App();
app.InitializeComponent();
app.Run();
}
//Marking this as [STAThread] will cause RPC_E_TOO_LATE
internal static void Main()
{
//This call won't throw an RPC_E_TOO_LATE COMException anymore
NativeMethods.Initialize();
/*
We will have to create a GUI thread manually here
since the COM threading model isn't STA for this thread
*/
Thread guiThread = new Thread(STAMain);
guiThread.SetApartmentState(ApartmentState.STA);
guiThread.Start();
}
免责声明:我不完全确定这个解决方案有多明智或明智,但它似乎允许应用程序正常工作,并且没有托管兼容模式。
我正在尝试 运行 应用程序在启动时调用 CoInitializeSecurity
。这在 Visual Studio 2013 年有效,但在 Visual Studio 2017 年无效 - 我很好奇为什么会这样。
在 Visual Studio 2017 年启动时调用 CoInitializeSecurity 时,我得到一个 COMException
,错误代码 RPC_E_TOO_LATE (0x80010119)
,表明已经对 CoInitialize
进行了调用,这Visual Studio 2013 年不会发生。
我在 Visual Studio 2013 年启用 Visual Studio 托管进程时或在调用 CoInitializeSecurity
之前加载使用 COM 的程序集时看到过此行为。
加载的程序集在 Visual Studio 2013 和 2017 之间有所不同(进入 App
构造函数时拍摄的快照),差异突出显示:
2013:
'WPFTestVS2017.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\WPFTestVS2017\bin\Debug\WPFTestVS2017.exe'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Xaml\v4.0_4.0.0.0__b77a5c561934e089\System.Xaml.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll'.
2017:
'WPFTestVS2017.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: DefaultDomain): Loaded 'C:\WPFTestVS2017\bin\Debug\WPFTestVS2017.exe'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\WindowsBase\v4.0_4.0.0.0__31bf3856ad364e35\WindowsBase.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Xaml\v4.0_4.0.0.0__b77a5c561934e089\System.Xaml.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\Program Files (x86)\Microsoft Visual Studio17\Enterprise\Common7\IDE\Remote Debugger\x64\Runtime\Microsoft.VisualStudio.Debugger.Runtime.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll'.
'WPFTestVS2017.exe' (CLR v4.0.30319: WPFTestVS2017.exe): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll'.
远程调试器让我产生了怀疑,因为它让我想起了 Visual Studio 托管进程。另一行不同的是 System.Core.dll
,它没有出现在 VS2013 的加载程序集中。
代码:
App.xaml
<Application x:Class="WPFTestVS2017.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
</Application>
App.xaml.cs
using System;
using System.Runtime.InteropServices;
using System.Windows;
namespace WPFTestVS2017
{
internal static class NativeMethods
{
private enum RpcAuthnLevel
{
Default = 0,
None = 1,
Connect = 2,
Call = 3,
Pkt = 4,
PktIntegrity = 5,
PktPrivacy = 6
}
private enum RpcImpLevel
{
Default = 0,
Anonymous = 1,
Identify = 2,
Impersonate = 3,
Delegate = 4
}
private enum EoAuthnCap
{
None = 0x0000,
MutualAuth = 0x0001,
StaticCloaking = 0x0020,
DynamicCloaking = 0x0040,
AnyAuthority = 0x0080,
MakeFullSIC = 0x0100,
Default = 0x0800,
SecureRefs = 0x0002,
AccessControl = 0x0004,
AppID = 0x0008,
Dynamic = 0x0010,
RequireFullSIC = 0x0200,
AutoImpersonate = 0x0400,
NoCustomMarshal = 0x2000,
DisableAAA = 0x1000
}
[DllImport("Ole32.dll",
ExactSpelling = true,
EntryPoint = "CoInitializeSecurity",
CallingConvention = CallingConvention.StdCall,
SetLastError = false,
PreserveSig = false)]
private static extern void CoInitializeSecurity(
IntPtr pVoid,
int cAuthSvc,
IntPtr asAuthSvc,
IntPtr pReserved1,
uint dwAuthnLevel,
uint dwImpLevel,
IntPtr pAuthList,
uint dwCapabilities,
IntPtr pReserved3);
public static void Initialize()
{
CoInitializeSecurity(IntPtr.Zero,
-1,
IntPtr.Zero,
IntPtr.Zero,
(uint)RpcAuthnLevel.PktPrivacy,
(uint)RpcImpLevel.Impersonate,
IntPtr.Zero,
(uint)EoAuthnCap.DynamicCloaking,
IntPtr.Zero);
}
}
public partial class App : Application
{
public App()
{
NativeMethods.Initialize();
}
}
}
MainWindow.xaml
<Window x:Class="WPFTestVS2017.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"/>
MainWindow.xaml.cs
using System.Windows;
namespace WPFTestVS2017
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
编辑:
我对App.xaml.cs
做了以下修改:
public App()
{
try
{
NativeMethods.Initialize();
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
消息框在 Visual Studio 2017 年调试时出现,但是,当 运行 在 Visual Studio.
之外运行相同的可执行文件时,它不会出现您正在与 VS2017 中托管调试引擎的变化作斗争。它与您猜测的内容没有任何关系,我认为删除 Visual Studio Hosting Process 选项可能是相关的。瞎猜,这是一个黑盒子,如果没有微软调试团队的帮助,很难被攻破。
您有几种可能的解决方法,按实用性排序:
工具 > 选项 > 调试 > 常规,勾选 "Use Managed Compatibility Mode" 复选框。这将用旧的调试引擎替换新的调试引擎,最后在 VS2010 中使用。您会错过一些最新的调试器功能(新的 PDB 格式、return 值检查、64 位编辑+继续),这些功能几乎不会阻止您调试 WPF 应用程序。
如果不需要,您可以阻止函数抛出异常。将 [DllImport] 的 PreserveSig 属性 更改为 true,将 return 类型从 void 更改为 int。它仍然会失败,由负 return 值指示,但您可以继续调试其余代码。也许您想使用 return 值来设置您用来绕过棘手的 COM 代码的全局变量。
如果不需要,您可以延迟初始化调试引擎,直到 CoInitializeSecurity 调用之后。追加
System.Diagnostics.Debugger.Launch();
,用#if DEBUG
包裹。现在您可以按 Ctrl+F5 开始调试,当您得到提示时,select VS 的 运行 实例作为所需的调试器。使用“调试”>“附加到进程”是类似的解决方法。
我终于设法找到了这个问题的解决方案 - 这个问题似乎起源于 STAThread
。
在 App.xaml
的属性中将构建操作从 ApplicationDefinition
切换到 Page
允许我们定义自己的 Main
方法,而不是使用 compiler-generated App.g.cs
.
仍然使用问题中的NativeMethods
class作为参考:
internal static class NativeMethods
{
private enum RpcAuthnLevel
{
Default = 0,
None = 1,
Connect = 2,
Call = 3,
Pkt = 4,
PktIntegrity = 5,
PktPrivacy = 6
}
private enum RpcImpLevel
{
Default = 0,
Anonymous = 1,
Identify = 2,
Impersonate = 3,
Delegate = 4
}
private enum EoAuthnCap
{
None = 0x0000,
MutualAuth = 0x0001,
StaticCloaking = 0x0020,
DynamicCloaking = 0x0040,
AnyAuthority = 0x0080,
MakeFullSIC = 0x0100,
Default = 0x0800,
SecureRefs = 0x0002,
AccessControl = 0x0004,
AppID = 0x0008,
Dynamic = 0x0010,
RequireFullSIC = 0x0200,
AutoImpersonate = 0x0400,
NoCustomMarshal = 0x2000,
DisableAAA = 0x1000
}
[DllImport("Ole32.dll",
ExactSpelling = true,
EntryPoint = "CoInitializeSecurity",
CallingConvention = CallingConvention.StdCall,
SetLastError = false,
PreserveSig = false)]
private static extern void CoInitializeSecurity(
IntPtr pVoid,
int cAuthSvc,
IntPtr asAuthSvc,
IntPtr pReserved1,
uint dwAuthnLevel,
uint dwImpLevel,
IntPtr pAuthList,
uint dwCapabilities,
IntPtr pReserved3);
public static void Initialize()
{
CoInitializeSecurity(IntPtr.Zero,
-1,
IntPtr.Zero,
IntPtr.Zero,
(uint)RpcAuthnLevel.PktPrivacy,
(uint)RpcImpLevel.Impersonate,
IntPtr.Zero,
(uint)EoAuthnCap.DynamicCloaking,
IntPtr.Zero);
}
}
新的 Main
方法需要首先调用 CoInitializeSecurity
,如下所示:
internal static void Main()
{
NativeMethods.Initialize();
}
这里缺少一些东西,比如之前 运行 在 compiler-generated Main
中的逻辑。当我们调用 CoInitializeSecurity
时,我们现在需要 运行 具有 STA 线程模型的线程中的 App
构造函数,如下所示:
[DebuggerNonUserCode]
internal static void STAMain()
{
//This is what the compiler-generated Main method executes by default
App app = new App();
app.InitializeComponent();
app.Run();
}
//Marking this as [STAThread] will cause RPC_E_TOO_LATE
internal static void Main()
{
//This call won't throw an RPC_E_TOO_LATE COMException anymore
NativeMethods.Initialize();
/*
We will have to create a GUI thread manually here
since the COM threading model isn't STA for this thread
*/
Thread guiThread = new Thread(STAMain);
guiThread.SetApartmentState(ApartmentState.STA);
guiThread.Start();
}
免责声明:我不完全确定这个解决方案有多明智或明智,但它似乎允许应用程序正常工作,并且没有托管兼容模式。