2016-10-25 2 views
2

У меня есть исполняемый файл C#, который загружается в DLL, которая является unicode неуправляемой C++ DLL. Эта неуправляемая C++ DLL также ссылается на другую DLL, неуправляемую DLL на C++, которая, как оказалось, является ANSI.C# EXE w/Unmanaged C++ Unicode DLL ссылка на неуправляемый C++ ANSI DLL crash

Когда я запускаю свой исполняемый файл C#, программа заканчивается сбоем в ANSI-части DLL-вызовов (пока я еще не смог удалить исключение). Однако, просто переключив ANSI DLL на Unicode, все работает, за исключением того факта, что есть третья DLL, которая из SDK от другой компании, которая имеет очевидную чувствительность к unicode/ANSI, поэтому она лучше всего работает, если вызывающая DLL находится в ANSI.

Итак, у нас есть одна исполняемая функция вызова только в одной неуправляемой DLL-библиотеке Unicode, которая служит в качестве оболочки для неуправляемой ANSI C++ DLL, которая является оболочкой для последней неуправляемой DLL, о которой у нас нет информации.

Переключение двух промежуточных библиотек DLL в уникод исправляет сбой только в случае его отказа с третьей отдельной DLL-производителем (но не катастрофически с исключением, они просто выводятся неправильно). Мы не можем переключить первую DLL на ANSI, потому что мы используем Unicode в нашем приложении C#, и это наш стандарт по всем направлениям.

Я не понимаю чувствительность к DLL второго порядка. Может кто-то пролить свет на это для меня?

Я использую этот класс, чтобы динамически связать в DLL файлы:

static class NativeMethods 
     { 
      [DllImport("kernel32", SetLastError = true)] 
      public static extern bool FreeLibrary(IntPtr hModule); 

      [DllImport("kernel32", SetLastError = true)] 
      public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); 

      [DllImport("kernel32", SetLastError = true)] 
      public static extern IntPtr LoadLibrary(string dllToLoad); 
     } 

с делегатами, похожими на:

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)] 
     private delegate int ExampleFunction(); 

и переключение CharSet.Auto к .Ansi или .Unicode не имеет никакого эффекта.

с вызовами функций и такие:

m_pDll = NativeMethods.LoadLibrary(@strDLLName); 
       if (m_pDll == IntPtr.Zero) this.Close(); 

       IntPtr pAddressForExampleFunction = NativeMethods.GetProcAddress(m_pDll, "ExampleFunction"); 
       if (pAddressForExampleFunction == IntPtr.Zero) this.Close(); 
m_ExampleFunction = (ExampleFunction)Marshal.GetDelegateForFunctionPointer(pAddressForExampleFunction, typeof(ExampleFunction)); 

с вызовом функции:

m_ExampleFunction(); 

в другом месте в коде.

Edit:

В соответствии с просьбой C++ EXE Контрагент:

В файле .h, определяется как члена:

ExampleFunction pExampleFunction; 

с

typedef BOOL __declspec(dllimport) (*ExampleFunction)(); 

pExampleFunction определяется как:

pExampleFunction= (ExampleFunction) ::GetProcAddress(m_hDll,"ExampleFunction"); 

, используя этот вызов, до:

m_hDll = AfxLoadLibrary(m_DllName); 
+0

(...) Тем не менее, просто переключая ANSI DLL в Unicode, все работает для того, что есть третья DLL, которая из SDK от другой компании, которая имеет кажущуюся чувствительность к кроме unicode/ANSI, поэтому он лучше всего работает, если вызывающая DLL находится в ANSI. (...) Это утверждение для меня не имеет смысла ... если эта третья dll не является COM-объектом, который вы используете через библиотеку типов, существует только один правильный способ передать строковые параметры для функций из этой DLL. Если вы передадите неправильный тип строки, он будет аварийно завершен. – yms

+0

Даже если эта «чувствительная» dll предоставляет функции ansi и unicode (примерA (LPCSTR val) vs exampleW (LPCWSTR val)), вашей «клиентской» dll по-прежнему необходимо будет выбрать нужную функцию в соответствии с конфигурацией сборки. – yms

+0

Для строгого читателя: Я знаю, что я «злоупотребляю» термином «Юникод» здесь ... пожалуйста, не сосредотачивайтесь на этом. – yms

ответ

2

Скорее всего, проблема происходит между двумя неуправляемыми библиотеками DLL, поскольку передача строки данных между ними несовместима.

Флаг dll ANSI/Unicode является свойством времени компиляции. Компилятор выбирает типы и функции в зависимости от этого флага.TCHAR для Unicode составлен как wchar_t и для ANSI это char. Например. такая разница может вызвать проблему, связанную с проблемой, если одна dll ожидает получить wchar_t* с длиной в символах, но фактическое принятое значение равно char*. Это неопределенное поведение и может привести к сбою приложения.

Также многие функции Win API имеют две версии xxxW для Unicode и xxxA для ANSI. Например:

#ifdef UNICODE 
    #define MessageBox MessageBoxW 
#else 
    #define MessageBox MessageBoxA 
#endif. 

На стороне C# CharSet атрибута управляет строки маршалингом и определяет, как платформа Invoke находит имена функций в DLL. Это не влияет на дальнейшие манипуляции строками внутри неуправляемой dll C++. Метод

[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Auto)] 
private delegate int ExampleFunction(); 

не имеет строк маршала, так CharSet не влияет на это. Может быть разница, если у вас есть две реализации этого метода на вашей неуправляемой стороне C++: ExampleFunctionA для ANSI и ExampleFunctionW для Unicode.

+0

Я согласен, что это, вероятно, происходит со строковой передачей данных между двумя DLL. Тем не менее, есть что-то еще: у меня есть C++ EXE, который проходит через ANSI/UNICODE, и он работает, на самом деле. Таким образом, есть что-то особенное C#, которое вызывает эту проблему. – RootAtShell

+1

@RootAtShell Обновлен мой ответ с дополнительной информацией об атрибуте 'CharSet'. Скорее всего, C++ EXE или C# EXE не должны иметь разницы. Все может случиться, если у вас есть Undefined Behavior, он может работать в C++ EXE Debug, но не в Release, или в некоторых непредсказуемых местах. – Nikita

+0

Хотя я бы согласился с этим утверждением, у нас не было непредсказуемого поведения на стороне C++ EXE. Теперь я понимаю, что отсутствие наблюдаемых проблем не означает, что проблем нет, но в этом случае это было 2+ года в тестировании и разработке, проходя через все наши тесты. Сейчас мы просто создаем аналог C# и вдруг имеем эти проблемы. Кажется очень странным, что мы не сталкиваемся с проблемами в течение 2 лет, чтобы постоянно ссориться все время. – RootAtShell

Смежные вопросы