C# 中调用c++DLL 问题

老鼠爱上猫 2006-05-16 10:21:48
c++ 接口入下
有两个结构体
typedef struct
{
unsigned long length;
unsigned char *value;
} SPT_DATA;

typedef struct
{
SPT_DATA CertCont[7]; //证书常用dn项DN(C/S/L/O/OU/CN/E)
SPT_DATA sn; //sn
SPT_DATA othername; //证书别名
} CertContStruct;

调用的接口 的一个参数是上面的结构体
EXTERN_SPI int C_ASPI_GetCertInfo(unsigned char *pCert, //设为NULL
unsigned char *pMode,
unsigned char *pCertContent,
CertContStruct *pCertConstantStruct);

想在C#里调用这个接口 ,
我先定义了两个对应的结构体

[StructLayout(LayoutKind.Auto)]
public struct SPT_DATA
{
public int length;
public byte[] valu;
}
[StructLayout(LayoutKind.Auto)]
public struct CertContStruct
{
public SPT_DATA[] CertCont ; //证书常用dn项DN(C/S/L/O/OU/CN/E)
public SPT_DATA sn ; //sn
public SPT_DATA othername; //证书别名
}

然后导入 DLL
[DllImport("CAspiDll_C.dll"]
private static extern int C_ASPI_GetCertInfo(byte[] pCert,byte[] pMode,byte[] pCertContent,CertContStruct pCertConstantStruct );

怎么来调这个方法:我调的时候提示我 结构体传不过去,没有实力化,

CertContStruct CCS = new CertContStruct();
CCS.CertCont.Length =1024;
CCS.CertCont.valu = new byte[1024];
CCS.CertCont= new SPT_DATA[7];
CCS.othername.length = 1024;
CCS.othername.valu =new byte[1024];
CCS.sn.length = 1024;
CCS.sn.valu = new byte[1024];
byte[] pc= new byte[4096*2];
byte[] pCC = new byte[2048];
byte[] pm = new byte[10];
pm = System.Text.Encoding.ASCII.GetBytes(pMode);//pMode是传入的字符串
pc = System.Text.Encoding.ASCII.GetBytes(C_ASPI_GetUserCert()); //C_ASPI_GetUserCert 也是返回字符串
int pCCLength = pCC.Length;
int j = C_ASPI_GetCertInfo(pc,pm,pCC,CCS);//到这就出错了.对象没有实例化
if(j==0)
{
pCertContent = System.Text.Encoding.ASCII.GetString(pCC,0,pCCLength);
pCertConstantStruct = CCS;
}


我觉得我的问题出在结构体的初始化,里面有数组,我实在不知道怎么初始化这些参数,
...全文
381 22 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
老鼠爱上猫 2006-05-18
  • 打赏
  • 举报
回复
我今天还做了一个测试就是
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct test1
{
public string str1;
public string str 2;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct test2
{
public test1 ss1;
public test ss2;
pullic sting ss3;
}

[DllImport( "teststruct.dll" )]
public static extern int TestArrayStruct(string str1,test2 stu1);

测试也是没有问题的。不过也算是向问题迈进了一步,

老鼠爱上猫 2006-05-18
  • 打赏
  • 举报
回复
暂时 先不结贴,如果这个周末,哪位高人,有好的方法,最好不过了,我也继续在寻找这方面的资料。希望也与大家分享,同时有这类问题的人也可以一起研究
老鼠爱上猫 2006-05-18
  • 打赏
  • 举报
回复
关键对方公司,提供的接口就是这样两个结构体,我传进去了,他把对应数据赋到这两个结构体里,然后我在去用这两个结构体里的数据,结构体是要在他的方法里 用的。没有办法了,所以现在我只能是 看看C++ 然后用C++ 再次封装他的方法,做新的接口,C++ 调用他的接口是没有问题的,所以现在我的解决方法,就是 用C++ 再次封装他的方法,使其只需要传入一个字符串组成的结构体,就OK了,这样最少知道,C++ 是可以实现的,所以正在研究C++呢,哈哈 …… 憋了4天了,2天的工作任务,弄了这么久,打算明天把新接口做完,然后剩下的就是小 意思了,哈哈,谢谢大家的关注!!!!!
Ninputer 2006-05-18
  • 打赏
  • 举报
回复
有数组的结构体就是托管结构体,不再具备和非托管直接映射的能力。这种托管结构体的数组作为另一个结构体的成员可能是不支持的。你最好手动去掉第一层结构体里的数组,反正去掉还是有办法访问的。
zsjzfq 2006-05-18
  • 打赏
  • 举报
回复
关注
-渔民- 2006-05-17
  • 打赏
  • 举报
回复
up
woyaomoney 2006-05-17
  • 打赏
  • 举报
回复
mark
Ninputer 2006-05-17
  • 打赏
  • 举报
回复
倒是还有办法就是了,不过会变得比较烦。SPT_DATA可以分别试验下列做法

public struct SPT_DATA
{
public int length;
public IntPtr value;
}

public unsafe struct SPT_DATA
{
public int length;
public byte* value;
}

然后CertContStruct结构仍值得试验我的和littlegang(Gang)的方案
老鼠爱上猫 2006-05-17
  • 打赏
  • 举报
回复
试了,很多方法,在没有数组的情况下还可以,但结构体里有数组,就是过不去,littlegang(Gang) ,和Ninputer(装配脑袋) 方法都试 过了,还是 过不去,报的错误还是一样 "无法封送类型 Ninetowns.Security.CertContStruct 的字段 CertCont:该类型无法作为结构字段进行封送处理。"谢谢大家的支持!
老鼠爱上猫 2006-05-17
  • 打赏
  • 举报
回复
我测试了 结构体里有数组的还是没有问题的
//定义结构体如下
public struct MyArrayStruct
{
public bool flag;
[ MarshalAs( UnmanagedType.ByValArray, SizeConst=3 )]
public int[] vals;
}

//导入DLL ,DLL是 VS.NET 2003 下自带的DLL
//SDK\v1.1\Samples\Technologies\Interop\PlatformInvoke\Custom\LIB
[DllImport( "PinvokeLib.dll" )]
public static extern int TestArrayInStruct( ref MyArrayStruct myStruct );

public static void Test()
{
MyArrayStruct myStruct = new MyArrayStruct();
myStruct.flag = false;
myStruct.vals = new int[ 3 ];
myStruct.vals[ 0 ] = 1;
myStruct.vals[ 1 ] = 4;
myStruct.vals[ 2 ] = 9;
int i = TestArrayInStruct( ref myStruct );
if(i <0)
{
MessageBox.Show("This is false !");
}
else
{
MessageBox.Show("This is ok!")
}
}

这个测试没有问题,所以我分析我的问在于用第一个结构体在第二个结构体 声明数组!
老鼠爱上猫 2006-05-17
  • 打赏
  • 举报
回复
经过多次测试,觉得问题在于结构体里 这个数组,查了多方材料没有相应的说明,在怀疑c# 调用c++的DLL,结构体参数中 的允许有数组吗,或者调数组是不是有什么特别的方法,现能想到的方法都试 过了,根据报的错误:
无法封送类型 Ninetowns.Security.CertContStruct 的字段 CertCont:该类型无法作为结构字段进行封送处理。"

得出这样一个猜想 !
littlegang 2006-05-16
  • 打赏
  • 举报
回复
干脆全部展开
public struct CertContStruct
{
public SPT_DATA CertCont1;
public SPT_DATA CertCont2;
public SPT_DATA CertCont3;
public SPT_DATA CertCont4;
public SPT_DATA CertCont5;
public SPT_DATA CertCont6;
public SPT_DATA CertCont7;
public SPT_DATA sn; //sn
public SPT_DATA othername; //证书别名
}
diandian82 2006-05-16
  • 打赏
  • 举报
回复
up
老鼠爱上猫 2006-05-16
  • 打赏
  • 举报
回复
CCS.CertCont = new SPT_DATA[7];
for(int i=0;i<7;i++)
{
CCS.CertCont[i].length1 =1024;
CCS.CertCont[i].value1 = new StringBuilder();
}
CCS.othername.length1 = 1024;
CCS.othername.value1 = new StringBuilder();
CCS.sn.length1 = 1024;
CCS.sn.value1 = new StringBuilder();

string pc = string.Empty;
pc = C_ASPI_GetUserCert();
string pCC = string.Empty;
int j = C_ASPI_GetCertInfo(pc,pMode,pCC,ref CCS);


报的错误是 "无法封送类型 Ninetowns.Security.CertContStruct 的字段 CertCont:该类型无法作为结构字段进行封送处理。"
老鼠爱上猫 2006-05-16
  • 打赏
  • 举报
回复
to :Ninputer(装配脑袋)
我的结构体按你的方法修改过了,
初始化的时候,怎样给他们初始化
我是这么写的:
CertContStruct CCS = new CertContStruct();
CCS.CertCont = new SPT_DATA[7];

CCS.othername.length = 1024;
CCS.othername.value = new StringBuilder();
CCS.sn.length = 1024;
CCS.sn.value = new StringBuilder();
string pc = string.Empty;
pc = C_ASPI_GetUserCert();//返回字符串
string pCC = string.Empty;
int j = C_ASPI_GetCertInfo(pc,pMode,pCC,ref CCS);
Ninputer 2006-05-16
  • 打赏
  • 举报
回复
前面那个结构也得改一下:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct SPT_DATA
{
public int length;
[MarshalAs(UnmanagedType.LPStr)] public StringBuilder value;
}

public struct CertContStruct
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=7)] public SPT_DATA[] CertCont; //证书常用dn项DN(C/S/L/O/OU/CN/E)
public SPT_DATA sn; //sn
public SPT_DATA othername; //证书别名
}

初始化SPT_DATA的时候,先给length赋值,然后用同样的值初始化StringBuilder。初始化CertContStruct的时候CertCont初始化为长度7的数组
Ninputer 2006-05-16
  • 打赏
  • 举报
回复
先把你的两个结构体声明上[StructLayout(LayoutKind.Auto)]都去掉
然后把API声明改成

[DllImport("CAspiDll_C.dll", CharSet=CharSet.Ansi)]
private static extern int C_ASPI_GetCertInfo(string pCert, string pMode, string pCertContent, ref CertContStruct pCertConstantStruct);

后面用的时候,凡是原来byte[]的参数都直接传string,会被自动Marshal成\0结尾的char*

然后那个CCS用ref传
Knight94 2006-05-16
  • 打赏
  • 举报
回复
不过你的每个struct类型都有数组,调用起来比较麻烦。
Knight94 2006-05-16
  • 打赏
  • 举报
回复
Sorry!
[StructLayout(LayoutKind.Auto)]
public struct CertContStruct
{
public SPT_DATA[] CertCont ; //证书常用dn项DN(C/S/L/O/OU/CN/E)
public SPT_DATA sn ; //sn
public SPT_DATA othername; //证书别名
public CertContStruct( int Num )
{
CertCont = new SPT_DATA[Num];
for( int i = 0; i < Num; i++ )
{
CertCont = new SPT_DATA();
// init its value
}
}
}
Knight94 2006-05-16
  • 打赏
  • 举报
回复
[StructLayout(LayoutKind.Auto)]
public struct SPT_DATA
{
public int length;
public byte[] valu;
}
[StructLayout(LayoutKind.Auto)]
public struct CertContStruct
{
public SPT_DATA[] CertCont ; //证书常用dn项DN(C/S/L/O/OU/CN/E)
public SPT_DATA sn ; //sn
public SPT_DATA othername; //证书别名
public CertContStruct
{
CertCont = new SPT_DATA[7];
for( int i = 0; i < 7; i++ )
{
CertCont = new SPT_DATA();
// init its value
}
}
}
加载更多回复(2)

111,094

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧