2016-01-11 4 views
3

У меня есть функция следующий C++ (принадлежит к COM-интерфейс, полученный от IUnknown), который я хочу позвонить из C# код:доступа исключение нарушения при вызове функции в Си ++ из C#

декларации C++ как документировано:

HRESULT Function1([in] STRUCT1 *s1, [in, out] STRUCT2 *s2, [in] SIZE_T var1); 

Декларация внутри рабочей C++ программе:

STDMETHOD(Function1)(
    THIS_ 
    __out STRUCT1 * s1, 
    __in_ecount_opt(var1) const STRUCT2 * s2, 
    SIZE_T var1 
    ) PURE; 

В # территории C определяю следующие:

[StructLayout(LayoutKind.Sequential)] 
public struct STRUCT1 
{ 
    public uint member1;  //HRESULT member1 
    public ulong member2;  //SIZE_T member2 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct STRUCT2 
{ 
    public IntPtr member1; //VOID *member1; 
    public ulong member2; //SIZE_T member2; 
    public STRUCT3 member3; //STRUCT3 member3; 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct STRUCT3 
{ 
    public int member1; //int member1 
} 

Я реализовать эту функцию в C# следующим образом:

[ComImport, ComVisible(false), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), 
Guid("…")] 
public interface Iinterface1 
{ 
…… 


    uint Function1(ref STRUCT1 s1, ref STRUCT2 s2, ulong var1); 
…… 
} 

и я вызвать функцию так:

  STRUCT1 temp1 = new STRUCT1(); 
      temp1.member1 = 0; 
      temp1.member2 = 0; 

      STRUCT2 temp2 = new STRUCT2(); 
      STRUCT3 temp3 = new STRUCT3(); 
      temp3.member1 = 0; 
      temp2.member1 = IntPtr.Zero; 
      temp2.member2 = 0; 
      temp2.member3 = temp3; 
      ulong var1 = 1; 

      res1 = COMobject.Function1(ref temp1, ref temp2, var1); 

При выполнении функции я получаю нарушение прав доступа Исключение:

«Необработанное исключение типа« System.AccessViolationException »произошло в prog1.exe Дополнительная информация: Попытка чтения или записи защищенной памяти. Это часто свидетельствует о том, что другая память повреждена. "

Я реализовал большинство функций одного и того же интерфейса без проблем, а также множество других интерфейсов в этом приложении. Это меня действительно озадачивает.

Я очень ценю вашу помощь по этому ..

Спасибо заранее.

+0

Вы можете посмотреть на http://manski.net/2012/06/pinvoke-tutorial-pinning-part-4/ –

+0

Вы должны использовать '' IntPtr' для SIZE_T' (необходимо только если он может работать на 32-битном процессоре, но в любом случае хорошая практика). Я также предлагаю вам дважды проверить, выполняется ли AccessViolationException в коде маршалинга или из самого метода com. –

+0

@Brian: Спасибо за ваши предложения.Можете ли вы предложить лучший способ удвоить проверку, если это происходит в процессе сортировки или в методе com? Я нацелен только на 64 бит, а исходный код метода com недоступен. – spsk

ответ

1

COM-Interop имеет довольно странный набор правил, вы должны действительно быть «в нем», чтобы рассуждать об этом. Многие вещи могут пойти не так, как надо, «тихо», и вам просто нужно разобраться с этим. В подобных ситуациях, вот что я хотел бы сделать, чтобы попытаться разобраться:

  1. Попробуйте использовать COM-интерфейс от PowerShell. Это дает хороший «второй POV», чтобы увидеть, может ли проблема быть в коде C#. Кроме того, обычно это намного проще проводить таким образом, нажимая различные данные.

  2. Сделайте некоторые отладки. Используйте трюк MessageBox(), чтобы остановить выполнение кода C++ в начале функции C++ (member), затем присоединить отладчик и посмотреть, что происходит.

  3. Предыдущий момент может занять много времени, иногда куча printfs параметров и другого состояния может помочь вам разобраться, что происходит. В сочетании с PowerShell у вас может быть много ресурсов и посмотреть, какие проблемы вызывают и какие проблемы.

+0

Спасибо Srdjan за ваши полезные предложения. Наконец-то я разобрал .dll и нашел проблему в элементе STRUCT3, описанном выше. Он должен иметь длину 64 бит, поскольку он хранит адрес памяти, и я работаю только с 64 битами. Еще раз спасибо за ваше время, помогая мне. – spsk