处理嵌入在 Visual C++ (MFC) 应用程序中的 .NET-ActiveX-Control
Disposing a .NET-ActiveX-Control embedded in a Visual C++ (MFC) application
我正在尝试将带有 WinForms 控件的第三方 .NET Framework 3.5 DLL 添加到我的非托管 Visual C++ MFC 应用程序中。因此,我构建了一个C# com-interop-wrapper DLL,注册为一个ActiveX控件。
运行良好,但每次退出MFC容器应用程序都会导致访问异常。
Exception thrown at 0x7B7E13C7 (mscorwks.dll) in MFCApplication2.exe: 0xC0000005: Access violation reading location 0xDDDDDDE5.
错误仅在我为事件添加接口时发生,即如果我添加属性 ComSourceInterface。下面的示例在没有 [ComSourceInterfaces(typeof(IUserControlEvents))]
.
行的情况下也能正常工作
这是最简单的例子:
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Reflection;
namespace WindowsFormsControlLibrary1
{
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
[Guid("F80C042C-ABEA-458D-96E0-F1A4DD620A72")]
public interface IUserControl
{
[DispId(1)]
void testMethod();
}
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
[Guid("CFF6DA90-2B8A-4D57-A4B8-581A47BA5226")]
public interface IUserControlEvents
{
[DispId(2)]
void click();
}
[ProgId("WindowsFormsControlLibrary1.UserControl1")]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IUserControl))]
[ComSourceInterfaces(typeof(IUserControlEvents))]
[ComVisible(true)]
[Guid("E5A1E243-AFD2-4443-8A54-D5FE9A8633C8")]
public partial class UserControl1: UserControl, IUserControl
{
[ComVisible(true)]
public delegate void UserControlClick();
public event UserControlClick click;
[ComVisible(true)]
public void testMethod()
{
MessageBox.Show("hallo");
}
public UserControl1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (click != null)
click();
}
[ComRegisterFunction()]
public static void RegisterClass(string i_Key)
{
i_Key = i_Key.Replace(@"HKEY_CLASSES_ROOT\", "");
// open the CLSID\{guid} key for write access
using (RegistryKey clsidRegisterKey = Registry.ClassesRoot.CreateSubKey(i_Key))
{
// and create the 'Control' key - this allows it to show up in
// the ActiveX control container
clsidRegisterKey.CreateSubKey("Control").Close();
// next create the CodeBase entry - needed if not string named and GACced.
using (RegistryKey inprocServer32 = clsidRegisterKey.CreateSubKey("InprocServer32"))
{
inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase);
}
using (RegistryKey miscStatus = clsidRegisterKey.CreateSubKey("MiscStatus"))
{
//??????
miscStatus.SetValue("", 0x20191);//0x00000801
}
using (RegistryKey typeLib = clsidRegisterKey.CreateSubKey("TypeLib"))
{
Guid libid = Marshal.GetTypeLibGuidForAssembly(typeof(UserControl1).Assembly);
typeLib.SetValue("", libid.ToString("B"));
}
using (RegistryKey version = clsidRegisterKey.CreateSubKey("Version"))
{
Marshal.GetTypeLibVersionForAssembly(typeof(UserControl1).Assembly, out int major, out int minor);
version.SetValue("", $"{major}.{minor}");
}
}
using (RegistryKey interfaceRegisterKey = Registry.ClassesRoot.CreateSubKey(@"Interface\" + typeof(IUserControl).GUID.ToString("B")))
{
interfaceRegisterKey.SetValue("", "IUserControl");
using (RegistryKey subkey = interfaceRegisterKey.CreateSubKey("TypeLib"))
{
Guid libid = Marshal.GetTypeLibGuidForAssembly(typeof(IUserControl).Assembly);
subkey.SetValue("", libid.ToString("B"));
}
using (RegistryKey subkey = interfaceRegisterKey.CreateSubKey("ProxyStubClsid32"))
{
subkey.SetValue("", "{00020420-0000-0000-C000-000000000046}");
}
}
using (RegistryKey interfaceRegisterKey = Registry.ClassesRoot.CreateSubKey(@"Interface\" + typeof(IUserControlEvents).GUID.ToString("B")))
{
interfaceRegisterKey.SetValue("", "IUserControlEvents");
using (RegistryKey subkey = interfaceRegisterKey.CreateSubKey("TypeLib"))
{
Guid libid = Marshal.GetTypeLibGuidForAssembly(typeof(IUserControlEvents).Assembly);
subkey.SetValue("", libid.ToString("B"));
}
using (RegistryKey subkey = interfaceRegisterKey.CreateSubKey("ProxyStubClsid32"))
{
subkey.SetValue("", "{00020420-0000-0000-C000-000000000046}");
}
}
}
[ComUnregisterFunction()]
public static void UnregisterClass(string i_Key)
{
i_Key = i_Key.Replace(@"HKEY_CLASSES_ROOT\", "");
try
{
Registry.ClassesRoot.DeleteSubKeyTree(i_Key);
}
catch (ArgumentException e)
{
}
try
{
Registry.ClassesRoot.DeleteSubKeyTree(@"Interface\" + typeof(IUserControl).GUID.ToString("B"));
}
catch (ArgumentException e)
{
}
try
{
Registry.ClassesRoot.DeleteSubKeyTree(@"Interface\" + typeof(IUserControlEvents).GUID.ToString("B"));
}
catch (ArgumentException e)
{
}
}
}
}
在我的 MFC 应用程序中,我通过“插入 ActiveX 控件”将 ActiveX 控件放置在主对话框中。不需要使用 class 向导添加控制变量。只要在编辑器中添加控件,异常就已经出现了
大多数时候异常发生在mscorwks.dll:
的SafeReleaseHelper方法中
mscorwks.dll!SafeReleaseHelper(struct IUnknown *,struct RCW *) Unknown
mscorwks.dll!SafeRelease(struct IUnknown *,struct RCW *) Unknown
mscorwks.dll!IUnkEntry::Free(struct RCW *,int) Unknown
mscorwks.dll!RCW::ReleaseAllInterfaces(void) Unknown
mscorwks.dll!RCW::ReleaseAllInterfacesCallBack(void *) Unknown
mscorwks.dll!RCW::Cleanup(void) Unknown
mscorwks.dll!RCWCleanupList::ReleaseRCWListRaw(struct RCW *) Unknown
mscorwks.dll!RCWCleanupList::ReleaseRCWListInCorrectCtx(void *) Unknown
mscorwks.dll!CtxEntry::EnterContextCallback(struct tagComCallData *) Unknown
combase.dll!CRemoteUnknown::DoCallback(tagXAptCallback * pCallbackData) Line 1882 C++
rpcrt4.dll!_Invoke@12() Unknown
rpcrt4.dll!_NdrStubCall2@16() Unknown
combase.dll!CStdStubBuffer_Invoke(IRpcStubBuffer * This, tagRPCOLEMESSAGE * prpcmsg, IRpcChannelBuffer * pRpcChannelBuffer) Line 1531 C++
[Inline Frame] combase.dll!InvokeStubWithExceptionPolicyAndTracing::__l6::<lambda_ee1df801181086a03fa4f8f75bd5617f>::operator()() Line 1279 C++
combase.dll!ObjectMethodExceptionHandlingAction<<lambda_ee1df801181086a03fa4f8f75bd5617f>>(InvokeStubWithExceptionPolicyAndTracing::__l6::<lambda_ee1df801181086a03fa4f8f75bd5617f> action, ObjectMethodExceptionHandlingInfo * pExceptionHandlingInfo, ExceptionHandlingResult * pExceptionHandlingResult, void *) Line 87 C++
[Inline Frame] combase.dll!InvokeStubWithExceptionPolicyAndTracing(IRpcStubBuffer * pMsg, tagRPCOLEMESSAGE *) Line 1277 C++
combase.dll!DefaultStubInvoke(bool bIsAsyncBeginMethod, IServerCall * pServerCall, IRpcChannelBuffer * pChannel, IRpcStubBuffer * pStub, unsigned long * pdwFault) Line 1346 C++
[Inline Frame] combase.dll!SyncStubCall::Invoke(IServerCall *) Line 1403 C++
[Inline Frame] combase.dll!SyncServerCall::StubInvoke(IRpcChannelBuffer *) Line 780 C++
[Inline Frame] combase.dll!StubInvoke(tagRPCOLEMESSAGE * pMsg, CStdIdentity * pStdID, IRpcStubBuffer *) Line 1628 C++
combase.dll!ServerCall::ContextInvoke(tagRPCOLEMESSAGE * pMessage, IRpcStubBuffer * pStub, CServerChannel * pChannel, tagIPIDEntry * pIPIDEntry, unsigned long * pdwFault) Line 1423 C++
[Inline Frame] combase.dll!CServerChannel::ContextInvoke(tagRPCOLEMESSAGE *) Line 1332 C++
[Inline Frame] combase.dll!DefaultInvokeInApartment(tagRPCOLEMESSAGE *) Line 3297 C++
combase.dll!ReentrantSTAInvokeInApartment(tagRPCOLEMESSAGE * pMsg, unsigned long dwCallCat, bool bIsTouchedASTACall, IRpcStubBuffer * pStub, CServerChannel * pChnl, tagIPIDEntry * pIPIDEntry, unsigned long * pdwFault) Line 113 C++
[Inline Frame] combase.dll!AppInvoke(ServerCall * pStub, CServerChannel *) Line 1122 C++
combase.dll!ComInvokeWithLockAndIPID(ServerCall * pServerCall, tagIPIDEntry * pIPIDEntry, bool * pbCallerResponsibleForRequestMessageCleanup) Line 2210 C++
[Inline Frame] combase.dll!ComInvoke(ServerCall *) Line 1697 C++
[Inline Frame] combase.dll!ThreadDispatch(ServerCall *) Line 414 C++
combase.dll!ThreadWndProc(HWND__ * window, unsigned int message, unsigned int wparam, long params) Line 740 C++
user32.dll!__InternalCallWinProc@20() Unknown
user32.dll!UserCallWinProcCheckWow() Unknown
user32.dll!DispatchMessageWorker() Unknown
user32.dll!_DispatchMessageW@4() Unknown
[Inline Frame] combase.dll!CCliModalLoop::MyDispatchMessage(tagMSG *) Line 2989 C++
combase.dll!CCliModalLoop::PeekRPCAndDDEMessage() Line 2616 C++
combase.dll!CCliModalLoop::FindMessage(unsigned long dwStatus) Line 2706 C++
combase.dll!CCliModalLoop::HandleWakeForMsg() Line 2302 C++
combase.dll!CCliModalLoop::BlockFn(void * * ahEvent, unsigned long cEvents, unsigned long * lpdwSignaled) Line 2239 C++
combase.dll!ClassicSTAThreadWaitForHandles(unsigned long dwFlags, unsigned long dwTimeout, unsigned long cHandles, void * * pHandles, unsigned long * pdwIndex) Line 51 C++
combase.dll!CoWaitForMultipleHandles(unsigned long dwFlags, unsigned long dwTimeout, unsigned long cHandles, void * * pHandles, unsigned long * lpdwindex) Line 122 C++
mscorwks.dll!NT5WaitRoutine(int,unsigned long,int,void * *,int) Unknown
mscorwks.dll!MsgWaitHelper(int,void * *,int,unsigned long,int) Unknown
mscorwks.dll!Thread::DoAppropriateAptStateWait(int,void * *,int,unsigned long,enum WaitMode) Unknown
mscorwks.dll!Thread::DoAppropriateWaitWorker(int,void * *,int,unsigned long,enum WaitMode) Unknown
mscorwks.dll!Thread::DoAppropriateWait(int,void * *,int,unsigned long,enum WaitMode,struct PendingSync *) Unknown
mscorwks.dll!CLREvent::WaitEx(unsigned long,enum WaitMode,struct PendingSync *) Unknown
mscorwks.dll!CLREvent::Wait(unsigned long,int,struct PendingSync *) Unknown
mscorwks.dll!_CorExitProcess@4() Unknown
mscorwks.dll!WaitForEndOfShutdown(void) Unknown
mscorwks.dll!EEShutDown(int) Unknown
mscorwks.dll!DisableRuntime(void) Unknown
mscorwks.dll!_CorExitProcess@4() Unknown
mscoreei.dll!RuntimeDesc::ShutdownAllActiveRuntimes(unsigned int,class RuntimeDesc *,enum RuntimeDesc::ShutdownCompatMode) Unknown
mscoreei.dll!_CorExitProcess@4() Unknown
mscoree.dll!_ShellShim_CorExitProcess@4() Unknown
ucrtbased.dll!try_cor_exit_process(const unsigned int return_code) Line 98 C++
ucrtbased.dll!exit_or_terminate_process(const unsigned int return_code) Line 139 C++
ucrtbased.dll!common_exit(const int return_code, const _crt_exit_cleanup_mode cleanup_mode, const _crt_exit_return_mode return_mode) Line 280 C++
ucrtbased.dll!exit(int return_code) Line 293 C++
> MFCApplication2.exe!__scrt_common_main_seh() Line 297 C++
MFCApplication2.exe!__scrt_common_main() Line 331 C++
MFCApplication2.exe!wWinMainCRTStartup(void * __formal) Line 17 C++
kernel32.dll!@BaseThreadInitThunk@12() Unknown
ntdll.dll!__RtlUserThreadStart() Unknown
ntdll.dll!__RtlUserThreadStart@8() Unknown
由于建立了双向连接(事件),.NET 持有对某些本机 COM 指针(由 MFC 提供)的引用。
如果 .NET 引用的 MFC 对象首先被删除,当 .NET 想要释放它的引用时(当发生不确定的垃圾收集时),为时已晚,它会在流氓指针上调用 IUnknown->Release()。
解决方案是调用 .NET 提供的本机方法:CoEEShutDownCOM 但如何调用它取决于 .NET Framework 版本。这是处理这两种情况的辅助方法:
#include "MetaHost.h"
HRESULT CoEEShutDownCOM()
{
typedef void(WINAPI* CoEEShutDownCOMfn)();
typedef HRESULT(WINAPI* CLRCreateInstanceFn)(REFCLSID, REFIID, LPVOID*);
HMODULE mscoree = GetModuleHandleW(L"mscoree.dll");
if (!mscoree)
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
CLRCreateInstanceFn createInstance = (CLRCreateInstanceFn)GetProcAddress(mscoree, "CLRCreateInstance");
if (createInstance)
{
// .NET 4+
ICLRMetaHost* host;
HRESULT hr = createInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&host));
if (FAILED(hr))
return hr;
IEnumUnknown* enumunk;
hr = host->EnumerateLoadedRuntimes(GetCurrentProcess(), &enumunk);
if (FAILED(hr))
{
host->Release();
return hr;
}
ICLRRuntimeInfo* info;
while (S_OK == enumunk->Next(1, (IUnknown**)&info, NULL))
{
CoEEShutDownCOMfn shutdown = NULL;
info->GetProcAddress("CoEEShutDownCOM", (LPVOID*)&shutdown);
if (shutdown)
{
shutdown();
}
info->Release();
}
enumunk->Release();
host->Release();
}
else
{
// other .NET
CoEEShutDownCOMfn shutdown = (CoEEShutDownCOMfn)GetProcAddress(mscoree, "CoEEShutDownCOM");
if (shutdown)
{
shutdown();
}
}
FreeLibrary(mscoree);
return S_OK;
}
您必须在 ActiveX 控件从 MFC 应用程序销毁之前调用它,例如当对话框被销毁时:
class CMFCApplication3Dlg : public CDialogEx
{
...
protected:
afx_msg void OnDestroy();
};
BEGIN_MESSAGE_MAP(CMFCApplication3Dlg, CDialogEx)
...
ON_WM_DESTROY()
END_MESSAGE_MAP()
void CMFCApplication3Dlg::OnDestroy()
{
CoEEShutDownCOM();
}
我正在尝试将带有 WinForms 控件的第三方 .NET Framework 3.5 DLL 添加到我的非托管 Visual C++ MFC 应用程序中。因此,我构建了一个C# com-interop-wrapper DLL,注册为一个ActiveX控件。
运行良好,但每次退出MFC容器应用程序都会导致访问异常。
Exception thrown at 0x7B7E13C7 (mscorwks.dll) in MFCApplication2.exe: 0xC0000005: Access violation reading location 0xDDDDDDE5.
错误仅在我为事件添加接口时发生,即如果我添加属性 ComSourceInterface。下面的示例在没有 [ComSourceInterfaces(typeof(IUserControlEvents))]
.
这是最简单的例子:
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Reflection;
namespace WindowsFormsControlLibrary1
{
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
[Guid("F80C042C-ABEA-458D-96E0-F1A4DD620A72")]
public interface IUserControl
{
[DispId(1)]
void testMethod();
}
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[ComVisible(true)]
[Guid("CFF6DA90-2B8A-4D57-A4B8-581A47BA5226")]
public interface IUserControlEvents
{
[DispId(2)]
void click();
}
[ProgId("WindowsFormsControlLibrary1.UserControl1")]
[ClassInterface(ClassInterfaceType.None)]
[ComDefaultInterface(typeof(IUserControl))]
[ComSourceInterfaces(typeof(IUserControlEvents))]
[ComVisible(true)]
[Guid("E5A1E243-AFD2-4443-8A54-D5FE9A8633C8")]
public partial class UserControl1: UserControl, IUserControl
{
[ComVisible(true)]
public delegate void UserControlClick();
public event UserControlClick click;
[ComVisible(true)]
public void testMethod()
{
MessageBox.Show("hallo");
}
public UserControl1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (click != null)
click();
}
[ComRegisterFunction()]
public static void RegisterClass(string i_Key)
{
i_Key = i_Key.Replace(@"HKEY_CLASSES_ROOT\", "");
// open the CLSID\{guid} key for write access
using (RegistryKey clsidRegisterKey = Registry.ClassesRoot.CreateSubKey(i_Key))
{
// and create the 'Control' key - this allows it to show up in
// the ActiveX control container
clsidRegisterKey.CreateSubKey("Control").Close();
// next create the CodeBase entry - needed if not string named and GACced.
using (RegistryKey inprocServer32 = clsidRegisterKey.CreateSubKey("InprocServer32"))
{
inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase);
}
using (RegistryKey miscStatus = clsidRegisterKey.CreateSubKey("MiscStatus"))
{
//??????
miscStatus.SetValue("", 0x20191);//0x00000801
}
using (RegistryKey typeLib = clsidRegisterKey.CreateSubKey("TypeLib"))
{
Guid libid = Marshal.GetTypeLibGuidForAssembly(typeof(UserControl1).Assembly);
typeLib.SetValue("", libid.ToString("B"));
}
using (RegistryKey version = clsidRegisterKey.CreateSubKey("Version"))
{
Marshal.GetTypeLibVersionForAssembly(typeof(UserControl1).Assembly, out int major, out int minor);
version.SetValue("", $"{major}.{minor}");
}
}
using (RegistryKey interfaceRegisterKey = Registry.ClassesRoot.CreateSubKey(@"Interface\" + typeof(IUserControl).GUID.ToString("B")))
{
interfaceRegisterKey.SetValue("", "IUserControl");
using (RegistryKey subkey = interfaceRegisterKey.CreateSubKey("TypeLib"))
{
Guid libid = Marshal.GetTypeLibGuidForAssembly(typeof(IUserControl).Assembly);
subkey.SetValue("", libid.ToString("B"));
}
using (RegistryKey subkey = interfaceRegisterKey.CreateSubKey("ProxyStubClsid32"))
{
subkey.SetValue("", "{00020420-0000-0000-C000-000000000046}");
}
}
using (RegistryKey interfaceRegisterKey = Registry.ClassesRoot.CreateSubKey(@"Interface\" + typeof(IUserControlEvents).GUID.ToString("B")))
{
interfaceRegisterKey.SetValue("", "IUserControlEvents");
using (RegistryKey subkey = interfaceRegisterKey.CreateSubKey("TypeLib"))
{
Guid libid = Marshal.GetTypeLibGuidForAssembly(typeof(IUserControlEvents).Assembly);
subkey.SetValue("", libid.ToString("B"));
}
using (RegistryKey subkey = interfaceRegisterKey.CreateSubKey("ProxyStubClsid32"))
{
subkey.SetValue("", "{00020420-0000-0000-C000-000000000046}");
}
}
}
[ComUnregisterFunction()]
public static void UnregisterClass(string i_Key)
{
i_Key = i_Key.Replace(@"HKEY_CLASSES_ROOT\", "");
try
{
Registry.ClassesRoot.DeleteSubKeyTree(i_Key);
}
catch (ArgumentException e)
{
}
try
{
Registry.ClassesRoot.DeleteSubKeyTree(@"Interface\" + typeof(IUserControl).GUID.ToString("B"));
}
catch (ArgumentException e)
{
}
try
{
Registry.ClassesRoot.DeleteSubKeyTree(@"Interface\" + typeof(IUserControlEvents).GUID.ToString("B"));
}
catch (ArgumentException e)
{
}
}
}
}
在我的 MFC 应用程序中,我通过“插入 ActiveX 控件”将 ActiveX 控件放置在主对话框中。不需要使用 class 向导添加控制变量。只要在编辑器中添加控件,异常就已经出现了
大多数时候异常发生在mscorwks.dll:
的SafeReleaseHelper方法中 mscorwks.dll!SafeReleaseHelper(struct IUnknown *,struct RCW *) Unknown
mscorwks.dll!SafeRelease(struct IUnknown *,struct RCW *) Unknown
mscorwks.dll!IUnkEntry::Free(struct RCW *,int) Unknown
mscorwks.dll!RCW::ReleaseAllInterfaces(void) Unknown
mscorwks.dll!RCW::ReleaseAllInterfacesCallBack(void *) Unknown
mscorwks.dll!RCW::Cleanup(void) Unknown
mscorwks.dll!RCWCleanupList::ReleaseRCWListRaw(struct RCW *) Unknown
mscorwks.dll!RCWCleanupList::ReleaseRCWListInCorrectCtx(void *) Unknown
mscorwks.dll!CtxEntry::EnterContextCallback(struct tagComCallData *) Unknown
combase.dll!CRemoteUnknown::DoCallback(tagXAptCallback * pCallbackData) Line 1882 C++
rpcrt4.dll!_Invoke@12() Unknown
rpcrt4.dll!_NdrStubCall2@16() Unknown
combase.dll!CStdStubBuffer_Invoke(IRpcStubBuffer * This, tagRPCOLEMESSAGE * prpcmsg, IRpcChannelBuffer * pRpcChannelBuffer) Line 1531 C++
[Inline Frame] combase.dll!InvokeStubWithExceptionPolicyAndTracing::__l6::<lambda_ee1df801181086a03fa4f8f75bd5617f>::operator()() Line 1279 C++
combase.dll!ObjectMethodExceptionHandlingAction<<lambda_ee1df801181086a03fa4f8f75bd5617f>>(InvokeStubWithExceptionPolicyAndTracing::__l6::<lambda_ee1df801181086a03fa4f8f75bd5617f> action, ObjectMethodExceptionHandlingInfo * pExceptionHandlingInfo, ExceptionHandlingResult * pExceptionHandlingResult, void *) Line 87 C++
[Inline Frame] combase.dll!InvokeStubWithExceptionPolicyAndTracing(IRpcStubBuffer * pMsg, tagRPCOLEMESSAGE *) Line 1277 C++
combase.dll!DefaultStubInvoke(bool bIsAsyncBeginMethod, IServerCall * pServerCall, IRpcChannelBuffer * pChannel, IRpcStubBuffer * pStub, unsigned long * pdwFault) Line 1346 C++
[Inline Frame] combase.dll!SyncStubCall::Invoke(IServerCall *) Line 1403 C++
[Inline Frame] combase.dll!SyncServerCall::StubInvoke(IRpcChannelBuffer *) Line 780 C++
[Inline Frame] combase.dll!StubInvoke(tagRPCOLEMESSAGE * pMsg, CStdIdentity * pStdID, IRpcStubBuffer *) Line 1628 C++
combase.dll!ServerCall::ContextInvoke(tagRPCOLEMESSAGE * pMessage, IRpcStubBuffer * pStub, CServerChannel * pChannel, tagIPIDEntry * pIPIDEntry, unsigned long * pdwFault) Line 1423 C++
[Inline Frame] combase.dll!CServerChannel::ContextInvoke(tagRPCOLEMESSAGE *) Line 1332 C++
[Inline Frame] combase.dll!DefaultInvokeInApartment(tagRPCOLEMESSAGE *) Line 3297 C++
combase.dll!ReentrantSTAInvokeInApartment(tagRPCOLEMESSAGE * pMsg, unsigned long dwCallCat, bool bIsTouchedASTACall, IRpcStubBuffer * pStub, CServerChannel * pChnl, tagIPIDEntry * pIPIDEntry, unsigned long * pdwFault) Line 113 C++
[Inline Frame] combase.dll!AppInvoke(ServerCall * pStub, CServerChannel *) Line 1122 C++
combase.dll!ComInvokeWithLockAndIPID(ServerCall * pServerCall, tagIPIDEntry * pIPIDEntry, bool * pbCallerResponsibleForRequestMessageCleanup) Line 2210 C++
[Inline Frame] combase.dll!ComInvoke(ServerCall *) Line 1697 C++
[Inline Frame] combase.dll!ThreadDispatch(ServerCall *) Line 414 C++
combase.dll!ThreadWndProc(HWND__ * window, unsigned int message, unsigned int wparam, long params) Line 740 C++
user32.dll!__InternalCallWinProc@20() Unknown
user32.dll!UserCallWinProcCheckWow() Unknown
user32.dll!DispatchMessageWorker() Unknown
user32.dll!_DispatchMessageW@4() Unknown
[Inline Frame] combase.dll!CCliModalLoop::MyDispatchMessage(tagMSG *) Line 2989 C++
combase.dll!CCliModalLoop::PeekRPCAndDDEMessage() Line 2616 C++
combase.dll!CCliModalLoop::FindMessage(unsigned long dwStatus) Line 2706 C++
combase.dll!CCliModalLoop::HandleWakeForMsg() Line 2302 C++
combase.dll!CCliModalLoop::BlockFn(void * * ahEvent, unsigned long cEvents, unsigned long * lpdwSignaled) Line 2239 C++
combase.dll!ClassicSTAThreadWaitForHandles(unsigned long dwFlags, unsigned long dwTimeout, unsigned long cHandles, void * * pHandles, unsigned long * pdwIndex) Line 51 C++
combase.dll!CoWaitForMultipleHandles(unsigned long dwFlags, unsigned long dwTimeout, unsigned long cHandles, void * * pHandles, unsigned long * lpdwindex) Line 122 C++
mscorwks.dll!NT5WaitRoutine(int,unsigned long,int,void * *,int) Unknown
mscorwks.dll!MsgWaitHelper(int,void * *,int,unsigned long,int) Unknown
mscorwks.dll!Thread::DoAppropriateAptStateWait(int,void * *,int,unsigned long,enum WaitMode) Unknown
mscorwks.dll!Thread::DoAppropriateWaitWorker(int,void * *,int,unsigned long,enum WaitMode) Unknown
mscorwks.dll!Thread::DoAppropriateWait(int,void * *,int,unsigned long,enum WaitMode,struct PendingSync *) Unknown
mscorwks.dll!CLREvent::WaitEx(unsigned long,enum WaitMode,struct PendingSync *) Unknown
mscorwks.dll!CLREvent::Wait(unsigned long,int,struct PendingSync *) Unknown
mscorwks.dll!_CorExitProcess@4() Unknown
mscorwks.dll!WaitForEndOfShutdown(void) Unknown
mscorwks.dll!EEShutDown(int) Unknown
mscorwks.dll!DisableRuntime(void) Unknown
mscorwks.dll!_CorExitProcess@4() Unknown
mscoreei.dll!RuntimeDesc::ShutdownAllActiveRuntimes(unsigned int,class RuntimeDesc *,enum RuntimeDesc::ShutdownCompatMode) Unknown
mscoreei.dll!_CorExitProcess@4() Unknown
mscoree.dll!_ShellShim_CorExitProcess@4() Unknown
ucrtbased.dll!try_cor_exit_process(const unsigned int return_code) Line 98 C++
ucrtbased.dll!exit_or_terminate_process(const unsigned int return_code) Line 139 C++
ucrtbased.dll!common_exit(const int return_code, const _crt_exit_cleanup_mode cleanup_mode, const _crt_exit_return_mode return_mode) Line 280 C++
ucrtbased.dll!exit(int return_code) Line 293 C++
> MFCApplication2.exe!__scrt_common_main_seh() Line 297 C++
MFCApplication2.exe!__scrt_common_main() Line 331 C++
MFCApplication2.exe!wWinMainCRTStartup(void * __formal) Line 17 C++
kernel32.dll!@BaseThreadInitThunk@12() Unknown
ntdll.dll!__RtlUserThreadStart() Unknown
ntdll.dll!__RtlUserThreadStart@8() Unknown
由于建立了双向连接(事件),.NET 持有对某些本机 COM 指针(由 MFC 提供)的引用。
如果 .NET 引用的 MFC 对象首先被删除,当 .NET 想要释放它的引用时(当发生不确定的垃圾收集时),为时已晚,它会在流氓指针上调用 IUnknown->Release()。
解决方案是调用 .NET 提供的本机方法:CoEEShutDownCOM 但如何调用它取决于 .NET Framework 版本。这是处理这两种情况的辅助方法:
#include "MetaHost.h"
HRESULT CoEEShutDownCOM()
{
typedef void(WINAPI* CoEEShutDownCOMfn)();
typedef HRESULT(WINAPI* CLRCreateInstanceFn)(REFCLSID, REFIID, LPVOID*);
HMODULE mscoree = GetModuleHandleW(L"mscoree.dll");
if (!mscoree)
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
CLRCreateInstanceFn createInstance = (CLRCreateInstanceFn)GetProcAddress(mscoree, "CLRCreateInstance");
if (createInstance)
{
// .NET 4+
ICLRMetaHost* host;
HRESULT hr = createInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&host));
if (FAILED(hr))
return hr;
IEnumUnknown* enumunk;
hr = host->EnumerateLoadedRuntimes(GetCurrentProcess(), &enumunk);
if (FAILED(hr))
{
host->Release();
return hr;
}
ICLRRuntimeInfo* info;
while (S_OK == enumunk->Next(1, (IUnknown**)&info, NULL))
{
CoEEShutDownCOMfn shutdown = NULL;
info->GetProcAddress("CoEEShutDownCOM", (LPVOID*)&shutdown);
if (shutdown)
{
shutdown();
}
info->Release();
}
enumunk->Release();
host->Release();
}
else
{
// other .NET
CoEEShutDownCOMfn shutdown = (CoEEShutDownCOMfn)GetProcAddress(mscoree, "CoEEShutDownCOM");
if (shutdown)
{
shutdown();
}
}
FreeLibrary(mscoree);
return S_OK;
}
您必须在 ActiveX 控件从 MFC 应用程序销毁之前调用它,例如当对话框被销毁时:
class CMFCApplication3Dlg : public CDialogEx
{
...
protected:
afx_msg void OnDestroy();
};
BEGIN_MESSAGE_MAP(CMFCApplication3Dlg, CDialogEx)
...
ON_WM_DESTROY()
END_MESSAGE_MAP()
void CMFCApplication3Dlg::OnDestroy()
{
CoEEShutDownCOM();
}