本机应用程序内的C#.NET用户控件.资源链问题

kje*_*lla 12 .net c++ mfc native wrapper

我正在包装一个MFC扩展DLL(MFCXDLL_2),以使其功能可供C#程序员使用.

包装器是"使用共享MFC DLL的常规DLL"和"公共语言运行时支持(/ clr)".(混合模式).

MFCXDLL_2中可用的类以MFCXDLL_3进行修饰.

我遇到的情况是在本机应用程序中运行的C#.NET用户控件中使用MFCXDLL_2的情况.

本机应用程序中的另一个MFC扩展DLL -MFCXDLL_1也使用MFCXDLL_2,这会导致麻烦.

当我启动本机应用程序时,它将隐式加载MFCXDLL_2.

当我加载.NET用户控件时,根据http://msdn.microsoft.com/en-us/library/ksa99t88.aspx,"使用数据库,OLE和套接字扩展"中的建议,再次显式加载相同的MFCXDLL_2.常规DLL中的DLL".

本机代码和.NET用户控件都实例化相同的类类型,并在MFCXDLL_2中调用相同的方法.

该方法对数据进行反序列化(通过共享内存接收)并将反序列化数据返回给调用者.这在本机代码中运行良好,直到我加载.NET用户控件.

加载.NET用户控件后,反序列化将停止使用本机代码,但从.NET用户控件调用时效果很好.

我将WinDbg附加到本机应用程序的调试版本并运行我的方案.在反序列化期间,WinDbg发现如下:

"警告:无法从存档加载.类未定义.CArchive异常:badClass."

我认为这里有一些资源问题所以我运行本机应用程序的发布版本加载MFCXDLL_2的发布版本.然后我加载.NET用户控件的调试版本 - 它再次将调试版本的MFCXDLL_2-加载到本机应用程序中.

然后一切都很好.由本机代码加载的MFCXDLL_2的一个发行版本和由.NET用户控件加载的一个MFCXDLL_2调试版本 - 在本机应用程序内运行.

那么发生了什么?是否无法在同一应用程序中同时从扩展DLL和常规DLL访问相同的MFCXDLL?
资源链是否以某种方式被破坏?有哪些可能的解决方案?

下面是一些代码,显示如何加载MFCXDLL_2 DLL
当本机应用程序启动时,调用MFCXDLL_2 DLLMain:

static AFX_EXTENSION_MODULE MFCXDLL_2 = { NULL, NULL };
static CDynLinkLibrary* gpDynLinkLibrary = NULL;

extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID )
{
  if (dwReason == DLL_PROCESS_ATTACH)
  {
        // Extension DLL one-time initialization
        AfxInitExtensionModule(MFCXDLL_2, hInstance);

        // Insert this DLL into the resource chain
        gpDynLinkLibrary = new CDynLinkLibrary(MFCXDLL_2);
  }
  else if (dwReason == DLL_PROCESS_DETACH)
  {
        if (gpDynLinkLibrary)
        {
              delete gpDynLinkLibrary;
              gpDynLinkLibrary = NULL;
        }
        // Terminate the library before destructors are called
        AfxTermExtensionModule(MFCXDLL_2);
  }
  return 1;   // ok
}
Run Code Online (Sandbox Code Playgroud)

加载.NET用户控件时,再次加载MFCXDLL_2 DLL:

//==============================================================
// Exported DLL initialization to run in context of Regular DLL.
// Must be called in InitInstance
// BOOL CYourRegularDLLApp::InitInstance()
//==============================================================
extern "C" _declspec(dllexport) CDynLinkLibrary* WINAPI InitMFCXDLL_2FromRegularDLL()
{
    if (gpDynLinkLibrary)
    {
        delete gpDynLinkLibrary;
        gpDynLinkLibrary = NULL;
     }
     // Create a new CDynLinkLibrary for this Regular DLL
     return new CDynLinkLibrary(MFCXDLL_2);
}
Run Code Online (Sandbox Code Playgroud)

在MFCXDLL_2中反序列化代码

    CMyClass* pMyclass = NULL; //CObject derived serializeable class
    BYTE *pBuf      = pGlobalCom->GetBuffer(); //Buffer with serialized CMyClass
    int nBufSize    = pGlobalCom->GetSize();   //Size of buffer

    CMemFile mf;
    mf.Attach(pBuf,nBufSize);

    CArchive ar(&mf, CArchive::load); //“Warning: Cannot load CMyClass from archive.  Class not defined.CArchive exception: badClass.”

    ar >> pMyclass; //CArchive exception thrown
    ar.Close();
    mf.Detach();
Run Code Online (Sandbox Code Playgroud)

图像显示了dll之间的关系.

在此输入图像描述

Chr*_*sBD 1

我认为您可能对您的包装器正在做什么感到困惑。

您可以使用 DLLImport 语句从 .NET 代码中调用非托管 C++ DLL。

我建议您创建一个 C# 类库项目,它将作为非托管 DLL MFCXDLL 的包装 DLL。

您可能无法将 DLL 添加为引用资源,但您应该创建一个项目文件夹来存储它并将其添加为项目文件,在构建 NET 类库时设置为 Copy Local True。您还需要将 MFCXDLL 引用的任何 DLL 放置在也设置为“复制本地”的同一文件夹中。

然后,您可以从所有基于 NET 的代码中引用您的 NET DLL。

是包装器过程的示例。

编辑

我已经检查过,是的,我使用了非托管 C++ DLL,它使用 MFC 作为共享库。这是我使用的代码的精简版本。(由于保密协议,一些类名称已更改。)

    using System.Collections.Generic;
    using System.Runtime.InteropServices;

    public class WrapperClass
    {
        [DllImport("some.dll", EntryPoint = "WriteDataCard", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.VariantBool)]
        public static extern Boolean WriteDataCard(Byte nComPort, bool bInitialize, bool bCardFeeder, [In] Byte[] bytesData, Byte dataSize, bool bTestKey);

        [DllImport("some.dll", EntryPoint = "ReadDataCard", SetLastError=true)]
        [return: MarshalAs(UnmanagedType.VariantBool)]
        public static extern Boolean ReadDataCard(Byte nComPort, Boolean bInitialize, Boolean bCardFeeder,  [Out] Byte[] bytesData, Byte dataSize);

   }
Run Code Online (Sandbox Code Playgroud)