当前位置:编程学习 > C#/ASP.NET >>

C# 调用 VC++的DLL是结构指针问题,求助

原本是用VC的Dll 近期要用C#来写,
VC 原版如下:
#define MAX_JUKEBOX_NAME 30
typedef struct
{
 UINT jbxId;
 UINT flags;

 UINT numDrives;
 UINT numSlots;
 UINT numMagazines;

 CHAR name [MAX_JUKEBOX_NAME];

} JBMSDK_JUKEBOX_T, *PJBMSDK_JUKEBOX_T;

UINT DLLENTRY
jbmGetJukeboxByNr (
 UINT jbxNr,
 ref PJBMSDK_JUKEBOX_T jukebox
);
改C#后 代码如下
        myClass.jbmClass.cs中如下:
        public const uint MAX_JUKEBOX_NAME=30;
        [StructLayout(LayoutKind.Sequential)]
        public struct JBMSDK_JUKEBOX_T
        {
            public uint jbxId;
            public uint flags;
            public uint numDrives;
            public uint numSlots;
            public uint numMagazines;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)MAX_JUKEBOX_NAME)]
            public char[] name;
        }
        [DllImport("jbmSdk.dll")]
        public static extern uint jbmGetJukeboxById (
         uint jbxId,
         IntPtr jukebox //PJBMSDK_JUKEBOX_T 
        );
ShowConnectStat.cs中:
        public ShowConnectStat_Form()
        {
            InitializeComponent();
            uint jbxNr = 0;
           
            myClass.jbmClass.JBMSDK_JUKEBOX_T jukeBox_t = new myClass.jbmClass.JBMSDK_JUKEBOX_T();
            

            IntPtr intP_jukeBox_t = Marshal.AllocHGlobal(Marshal.SizeOf(jukeBox_t));
            try
            {
                
                    Marshal.StructureToPtr(jukeBox_t, intP_jukeBox_t, false);
                    myClass.jbmClass.jbmGetJukeboxByNr(jbxNr, ref intP_jukeBox_t);
                    label6.Text = jukeBox_t.numDrives.ToString();
                
            }
            finally
            {
                Marshal.FreeHGlobal(intP_jukeBox_t);

            }

        }
结果内存无法对齐,

VC中的的结果应该是:                                       现在C#中 
Jukebox data:         jbxid: 8                        flage:45   
Flags: 1                      jbxid:1
Drives: 1                       其他字段都是空。
Slots: 45
Magazines: 3
Jukebox name: DISC1000

采用对齐方式后
 [StructLayout(LayoutKind.Explicit)]
        public struct JBMSDK_JUKEBOX_T
        {
            [FieldOffset(0)]
            public uint jbxId;
            [FieldOffset(4)]
            public uint flags;
            [FieldOffset(8)]
            public uint numDrives;
            [FieldOffset(12)]
            public uint numSlots;
            [FieldOffset(16)]
            public uint numMagazines;
            [FieldOffset(20)]
            [MarshalAs(UnmanagedType.ByValArray, SizeConst = (int)MAX_JUKEBOX_NAME)]
            public char[] name;
        }
   

flage:1 jbxid:1 其他字段还是空,请告诉帮忙

--------------------编程问答-------------------- 有过很多次这样的用法,从来没出现过问题,估计是C#结构设置的问题 --------------------编程问答-------------------- 这样可以???我第一次用VC DLL!还有其他办法吗? --------------------编程问答-------------------- VC中的的结果应该是:  
jbxid: 8 
Flags: 1 Drives: 1 
Slots: 45
Magazines: 3
Jukebox name: DISC1000
现在C#中 
flage:45 
jbxid:1
其他字段都是空。
   --------------------编程问答-------------------- 精确控制对齐,建议
[StructLayout(LayoutKind.Explicit)]
  public struct JBMSDK_JUKEBOX_T
  {
  [FieldOffset(0)]
  public uint jbxId;
  [FieldOffset(4)]
  public uint flags;
  [FieldOffset(8)]
  public uint numDrives;
  [FieldOffset(12)]
  public uint numSlots;
  [FieldOffset(16)]
  public uint numMagazines;
  [FieldOffset(20)]
  unsafe public fixed byte Name[MAX_JUKEBOX_NAME];
  }
vc中CHAR代表8位ansi字符,所在在.net中,需要使用byte进行封装,使用时候,使用
时需要Encoding.ASCII.GetString()方法转换为字符串

对于dll导出函数的调用方法,需要楼主将vc的dll导出函数声明贴出来进行参考才行 --------------------编程问答-------------------- vc中导出函数声明为cdecl时,函数声明的参数按照从右到左的顺序入栈,且由调用者清理堆栈,
声明stdcall导出时,函数声明的参数按照从左到右的顺序入栈,由函数内部负责清理堆栈,
fastcall代表使用寄存器ecx,edx作为第一个,和第二个参数,他不需要堆栈操作,但.net中已经不支持这样的调用。
所以我建议在.net中调用非托管代码时,尽量使用stdcall类型的导出函数(如果需要用可变大小参数除外,当然如果有也可以用指针)。你可以在指定的引入dll导出函数声明中这样写
(针对stdcall)
[DllImport("jbmSdk.dll",CharSet = CharSet.Auto)]
  public static extern uint jbmGetJukeboxById (
  uint jbxId,
  IntPtr jukebox //PJBMSDK_JUKEBOX_T  
  );

(针对cdecl,不建议,没变参,干嘛要用cdecl
[DllImport("jbmSdk.dll",CharSet = CharSet.Auto,CallingConvention=CallingConvention.Cdecl)]
  public static extern uint jbmGetJukeboxById (
  uint jbxId,
  IntPtr jukebox //PJBMSDK_JUKEBOX_T  
  ); --------------------编程问答-------------------- 方法是对的,至于原因只要看看数据在内存中的结构具体是什么,再调整一下对其就好了。

vs自带内存查看功能,直接查看一下指针所指向的内存,分析一下即可。 --------------------编程问答-------------------- mark
补充:.NET技术 ,  C#
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,