2012-07-03 129 views
0

我想学习足够的C#,以便可以通过引用传递一个结构C DLL;但它永远不会达到“c功能”。正如你可以在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. 你几乎肯定需要在DllImport属性来指定cdecl调用约定。添加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这很奇怪。那么我认为你需要在你的C++ Dll上使用stdcall。 – Botz3000

+0

@ Botz3000:尝试更改为__stdcall。同样的错误。 – PaeneInsula

0

[In, MarshalAs(UnmanagedType.LPStruct)]替换为ref

+0

好了,现在它读取:“公共静态extern无效cFunction(ref MPLOT mPlot)”我还必须添加“ref”关键字到param列表中,我调用cFunction:“cFunction(ref mPlot)”。同样的错误:“对象引用没有设置为对象的实例。” – PaeneInsula