Подтвердить что ты не робот

С#.NET User Control внутри собственного приложения. Проблемы с цепочкой ресурсов

Я завершаю расширение DLL MFC (MFCXDLL_2), чтобы сделать его функциональность доступной для программистов на С#.

Обертка - это "Обычная DLL, использующая совместно используемую библиотеку MFC DLL" с "Common Language Runtime Support (/clr)". (Смешанный режим).

Классы в MFCXDLL_2, которые должны быть доступны, оформляются в MFCXDLL_3.

Сценарий, который я испытываю, - это случай, когда MFCXDLL_2 используется из пользовательского элемента управления С#.NET, работающего в собственном приложении.

Другая MFC Extension DLL -MFCXDLL_1 внутри встроенного приложения также использует MFCXDLL_2, и это вызывает проблемы.

Когда я запускаю собственное приложение, он будет неявно загружать MFCXDLL_2.

Когда я загружаю пользовательский элемент управления .NET, тот же MFCXDLL_2 загружается снова явно в соответствии с рекомендацией в http://msdn.microsoft.com/en-us/library/ksa99t88.aspx, "Использование базы данных, OLE и расширения Sockets Extension DLL в обычных DLL файлах".

И собственный код, и пользовательский элемент управления .NET создают один и тот же тип класса и вызывают тот же метод в MFCXDLL_2.

Метод де-сериализует данные (полученные по общей памяти) и возвращает де-сериализованные данные вызывающему. Это отлично работает с собственным кодом, пока я не загружу пользовательский элемент управления .NET.

После загрузки пользовательского элемента управления .NET де-сериализация перестает работать с собственным кодом, но отлично работает при вызове из пользовательского элемента управления .NET.

Я подключил WinDbg к отладочной версии собственного приложения и запустил мой сценарий. WinDbg был найден следующим образом во время де-сериализации:

"Предупреждение: невозможно загрузить из архива. Класс не определен. Исключение CArchive: badClass. "

Я думаю, что здесь есть некоторые проблемы с ресурсами, поэтому я запускаю версию релиза собственного приложения, загружающую версию MFCXDLL_2. Затем я загружаю отладочную версию пользовательского элемента управления .NET, которая снова загружает отладочную версию MFCXDLL_2- в собственное приложение.

Тогда все просто отлично работает. Одна версия релиза MFCXDLL_2, загружаемая собственным кодом и одной отладочной версией MFCXDLL_2, загружаемой пользовательским элементом управления .NET, выполняется внутри собственного приложения.

Так что происходит? Невозможно ли получить доступ к тому же 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

4b9b3361

Ответ 1

Я думаю, что у вас может быть некоторая путаница в том, что делает ваша обертка.

Вы можете вызвать неуправляемые библиотеки С++ из .NET-кода с помощью операторов DLLImport.

Я бы предположил, что вы создаете проект библиотеки классов С#, который будет DLL-обложкой для вашей неуправляемой библиотеки DLL, MFCXDLL.

Вероятно, вы не сможете добавить DLL в качестве ресурса, на который ссылаетесь, но вы должны создать папку проекта, в которой вы ее сохранили, и добавить ее в качестве файла проекта, чтобы скопировать локальный True, когда была создана библиотека классов NET, Вы также захотите разместить любые DLL файлы, которые MFCXDLL ссылаются в одной и той же папке, также на "Копировать локальную".

Затем вы ссылаетесь на свою NET DLL из всего кода на основе NET.

Здесь пример процесса обертки.

изменить

У меня была проверка и да, я использовал неуправляемую 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);

   }