проблема с использованием неуправляемого C ++ из C # с использованием dllimport - PullRequest
0 голосов
/ 07 сентября 2010

У меня проблемы с импортом неуправляемой dll c ++ в C # [winform].Кто-то может помочь?

По сути, я просто пытаюсь создать безопасный список строк в c ++ и пытаюсь отправить его на C #.

Вот мой код на C ++.

extern "C" __declspec(dllexport) BOOL GetStringArr(SAFEARRAY* arr)
{
SAFEARRAY*    myArray;
  SAFEARRAYBOUND  rgsabound[1];

  rgsabound[0].lLbound = 0;
  rgsabound[0].cElements = 5;

  myArray = SafeArrayCreate(VT_BSTR, 1, rgsabound);
  VARIANT* pvData = (VARIANT*)(myArray->pvData);

  pvData[0].vt = VT_BSTR;
  pvData[0].bstrVal = SysAllocString(L"FirstString");
  pvData[1].vt = VT_BSTR;
  pvData[1].bstrVal = SysAllocString(L"SecondString");
  pvData[2].vt = VT_BSTR;
  pvData[2].bstrVal = SysAllocString(L"ThirdString");
  pvData[3].vt = VT_BSTR;
  pvData[3].bstrVal = SysAllocString(L"FourthString");
  pvData[4].vt = VT_BSTR;
  pvData[4].bstrVal = SysAllocString(L"FifthString");

  arr = myArray;
  return true;
}

Вот мой код на C #.

[DllImport("MyData.dll", EntryPoint = "GetStringArr")]
public static extern bool GetStringArr([MarshalAs(UnmanagedType.SafeArray)] out Array strServerList); 

Я получаю исключение при вызове GetStringArr из C #.Я уверен, что я делаю что-то глупое.Может кто-нибудь помочь, пожалуйста?

Заранее спасибо.

Ответы [ 4 ]

1 голос
/ 07 сентября 2010

Некоторые проблемы на стороне C и .NET

На стороне C

  1. Неверный аргумент косвенности. Поскольку вы выделяете дескриптор SAFEARRAY в функции, вам нужен SAFEARRAY **.
  2. SAFEARRAY не заполняется правильно. Вы создали дескриптор SAFEARRAY с базовым типом VT_BSTR, это означает, что элементы данных должны быть BSTR.

Код C

extern "C" __declspec(dllexport)
BOOL GetStringArr(SAFEARRAY** arr) 
{ 
  SAFEARRAY*    myArray; 
  SAFEARRAYBOUND  rgsabound[1]; 

  rgsabound[0].lLbound = 0; 
  rgsabound[0].cElements = 5; 

  myArray = SafeArrayCreate(VT_BSTR, 1, rgsabound); 
  BSTR* pvData = (BSTR*)(myArray->pvData); 

  pvData[0] = SysAllocString(L"FirstString"); 
  pvData[1] = SysAllocString(L"SecondString"); 
  pvData[2] = SysAllocString(L"ThirdString"); 
  pvData[3] = SysAllocString(L"FourthString"); 
  pvData[4] = SysAllocString(L"FifthString"); 

  *arr = myArray;
  return true; 
}

На стороне .NET

  1. Необходимо указать соглашение о вызовах, иначе у вас будут проблемы со стеком
  2. Вы должны установить SafeArraySubType
  3. Вы можете использовать out string[], чтобы получить указатель на SAFEARRAY

.NET код

  class Program
  {
    static void Main(string[] args)
    {
      string[] data;
      bool b = GetStringArr(out data);      
    }

    [DllImport("MyData.dll", 
               CallingConvention = CallingConvention.Cdecl)]
    public static extern bool GetStringArr(
      [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_BSTR)] 
      out string[] strServerList);    
  }
1 голос
/ 07 сентября 2010

Несколько проблем в вашем C ++ коде.Вы возвращаете массив, для которого требуется, чтобы аргумент был SAFEARRAY **.Вы также заполняете массив неверными данными, вы создали массив строк, но вы пишете VARIANT.Не уверен, что было задумано, я сохраню варианты в кодовом исправлении:

extern "C" __declspec(dllexport) BOOL GetStringArr(SAFEARRAY** arr)
{
  SAFEARRAY*    myArray;
  SAFEARRAYBOUND  rgsabound[1];

  rgsabound[0].lLbound = 0;
  rgsabound[0].cElements = 5;

  myArray = SafeArrayCreate(VT_VARIANT, 1, rgsabound);
  VARIANT* pvData = 0;
  SafeArrayAccessData(myArray, (void**)&pvData);

  pvData[0].vt = VT_BSTR;
  pvData[0].bstrVal = SysAllocString(L"FirstString");
  // etc..
  SafeArrayUnaccessData(myArray);

  *arr = myArray;
  return true;
}

C # код:

        object[] array;
        bool ok = GetStringArr(out array);

    [DllImport(@"blah.dll", EntryPoint = "GetStringArr")]
    [return: MarshalAs(UnmanagedType.U1)]
    public static extern bool GetStringArr([MarshalAs(UnmanagedType.SafeArray)] out object[] strServerList); 
0 голосов
/ 07 сентября 2010

Я рекомендую вам добавить проект C ++ / CLI (сборку) в ваше решение C #. Это позволит вам писать код, который живет одновременно на управляемой и неуправляемой земле. Это означает, что ваш код C ++ / CLI может вместо этого создать List<string^> и добавить к нему управляемые строки, прежде чем вы вернете его в C #. : -)

0 голосов
/ 07 сентября 2010

У вас есть доступ к исходному файлу DLL?Если это так, вы можете включить неуправляемую отладку в параметрах управляемых проектов и перейти к неуправляемому коду (предпочтительно, сборке отладки), чтобы увидеть, что происходит.Если ничего другого, вы можете включить исключения в опциях отладчика и отладить, чтобы увидеть, где выбрасывается собственное исключение.

...