2011-11-17 41 views
12

我正在封装一个MFC扩展DLL(MFCXDLL_2)以使其功能可供C#程序员使用。本机应用程序中的C#.NET用户控件。资源链问题

该包装是一个“使用共享MFC DLL常规DLL”与“公共语言运行库支持(/ CLR)”。 (混合模式)。

应该可用的MFCXDLL_2中的类在MFCXDLL_3中进行了修饰。

我遇到的情形是,MFCXDLL_2是从本地应用程序运行的C#.NET用户控制使用的情况下。

另一个MFC扩展DLL -MFCXDLL_1,里面的本地应用程序也使用MFCXDLL_2,这造成麻烦。

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

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

两个本机代码和.NET用户控制实例相同的类型,并调用在MFCXDLL_2相同的方法。

的方法,解串数据(通过共享存储器接收的)和去串行化的数据返回给调用者。直到我加载.NET用户控件时,这从原生代码很好地工作。

加载.NET用户控件后,反序列停止从本机代码的工作,但是从.NET用户控件调用时,它的伟大工程。

我将WinDbg附加到原生应用程序的调试版本并运行我的方案。 WinDbg在反序列化过程中发现如下:

“警告:无法从存档加载。类未定义。 CArchive的例外:badClass”

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

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

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

下面是该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 
} 

当。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); 
} 

的反序列化码内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(); 

所述的图像显示的DLL之间的关系。

enter image description here

回答

1

我认为,你可以在这里有些混乱,你的包装正在做。

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

我会建议你创建一个C#类库项目,这将是你的非托管的DLL,MFCXDLL包装DLL。

您可能不会能够将DLL添加为引用资源,但您应该创建一个项目文件夹,将其存储并添加为项目文件,设置为Copy Local True建成。您还需要将MFCXDLL在同一文件夹中引用的任何DLL也设置为“复制本地”。

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

Here是包装过程的一个例子。

编辑

我有一张支票,是我用的是使用MFC的共享库的非托管C++ DLL。下面是我使用的代码的削减版本。(有些类名称已更改由于保密协议。)

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); 

    } 
+0

我可以n要看到一个C#包装将如何解决这个问题。 它如何解决问题? 我遵循文章http://www.codeguru.com/cpp/cpp/cpp_managed/interop/article.php/c6867中给出的模式。 托管和非托管世界之间的实际桥梁是混合模式DLL。包装器只装饰我想要为.NET用户控件显示的类。 – kjella

+0

你说得对。照片错了。这当然是“常规DLL使用共享的MFC DLL”,这是包装。我现在改变了图片。 MFCXDLL_3装饰MFCXDLL_2中的一些类,并为用户控件创建必要的功能性。 – kjella

+0

您正在查看的CodeGuru模式是从2004年开始的。我非常确定它不再适用(至少在NET 3.5以上版本中)。我可以仔细检查我在另一台机器上的代码,稍后会回发。 – ChrisBD

相关问题