2012-07-03 2 views
0

Я пытаюсь узнать достаточно C#, чтобы передать strcture по ссылке на C DLL; но он никогда не попадает в «cFunction». Как вы видите в cFunction, я явно устанавливаю значение streamSubset равным 44; но в части C# он не возвращает «44». Вот код C:Передача структуры из C# в C dll

typedef struct s_mPlot 
{ 
    double  price[100]; 
    int   streamSubset; 
} mPlot; 

extern "C" __declspec(dllexport) 
void cFunction(mPlot *Mplot){ 
    Mplot->streamSubset = 44;} 

// и здесь C# код

using System; 
    using Vibe.Function; 
    using System.Runtime.InteropServices; 
    [StructLayout(LayoutKind.Sequential)] 
    public class MPLOT 
    { 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] 
     public double [] price; 
     public int   streamSubset; 
    } 

namespace Vibe.Indicator{ 
public class myIdx : IndicatorObject { 

    [DllImport("C:\\Users\\joe\\mcDll.dll", CharSet = CharSet.Auto)] 
    public static extern void cFunction(
    [In, MarshalAs(UnmanagedType.LPStruct)] MPLOT mPlot); 
    public myIdx(object _ctx):base(_ctx){} 
    private IPlotObject plot1; 

    protected override void Create() 
    { 
     MPLOT mPlot   = new MPLOT(); 
     mPlot.streamSubset = 2; 
     cFunction(mPlot); 

     if (mPlot.streamSubset == 44) 
      go(); 
    } 

} 

}

+0

Просьба представить более подробную информацию - то, что вы видите вместо этого? Сбой? Неожиданные результаты? Неверные данные? Вы пробовали отлаживать его? – reuben

+0

Код C# не может работать с использованием отладчика. Длительное объяснение, но это коммерческий продукт, который его предотвращает. – PaeneInsula

ответ

0

можно увидеть следующее:

  1. Вы почти наверняка нужно указать cdecl соглашение о вызовах в атрибуте DllImport. Добавить CallingConvention=CallingConvention.Cdecl.
  2. Я считаю, что UnmanagedType.LPStruct добавляет дополнительный уровень косвенности. Но вы передаете C# class, который является ссылочным типом. Это означает, что вы передаете указатель на указатель. Это один уровень косвенности слишком много. Прежде всего удалите [In, MarshalAs(UnmanagedType.LPStruct)]. Тогда ваш код должен работать. Если вы переключились на структуру, а не на класс для MPLOT, то вам нужно будет пройти мимо ref, чтобы получить косвенность.

Я думаю, что будет иметь такой код:

[StructLayout(LayoutKind.Sequential)] 
public struct MPLOT 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] 
    public double [] price; 
    public int   streamSubset; 
} 

[DllImport("dllname.dll", CallingConvention=CallingConvention.Cdecl)] 
public static extern void cFunction(
    ref MPLOT mPlot 
); 
+0

Нет, то, что вы предлагаете, тоже не работает. Я не могу найти никаких примеров этого в Интернете после поиска через десятки страниц ... начинаю думать, что это невозможно. – PaeneInsula

+0

Код в этом ответе определенно соответствует коду C++ в вашем вопросе. Напишите себе немного C++ DLL, чтобы доказать, что это так. То, что мы не можем видеть, здесь неправильно. То, что вы пытаетесь сделать, для маршалирования этой структуры тривиально легко достичь. –

+0

Я сделал то, что вы предложили, и вы правы. Я обнаружил, что в стороннем приложении есть ошибка, которая вызывает проблему. Спасибо за вашу помощь. – PaeneInsula

0

Попробуйте указать соглашение о вызовах в явном виде:

[DllImport("C:\\Users\\joe\\mcDll.dll", CallingConvention=CallingConvention.Cdecl CharSet = CharSet.Auto)] 

экспорт VC с вызывающим соглашением cdecl по умолчанию, но DllImport по умолчанию используется stdcall. Таким образом, вы должны указать хотя бы одно из них явно или лучше, оба.

+0

Пробовал добавить это, и я получаю это загадочное сообщение (из коммерческого продукта, а не vs2010): «Ссылка на объект не установлена ​​в экземпляр объекта» – PaeneInsula

+0

@ user994179 Это странно. Тогда я думаю, вам нужно использовать stdcall на вашей C++ Dll. – Botz3000

+0

@ Botz3000: попытался перейти на __stdcall. Такая же ошибка. – PaeneInsula

0

Заменить [In, MarshalAs(UnmanagedType.LPStruct)] на ref.

+0

Итак, теперь он читает: «public static extern void cFunction (ref MPLOT mPlot)» Мне также пришлось добавить ключевое слово «ref» в список параметров, где я вызываю cFunction: «cFunction (ref mPlot)». Еще одна ошибка: «Объект ref не установлен в экземпляр объекта». – PaeneInsula

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