电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

平台调用P-INVOKE完全掌握13


发布日期:2022/5/31
 

在使用结构体指针进行和的互相调用边界对齐是一个大问题因为边界对齐问题结构体的成员并不是顺序在一个挨着一个的排序

而且在C++中可以使用#pragma pack(n)改变边界对齐的方案那C#的结构体怎么对应C++的结构体那?(什么是边界对齐这里不解释

不懂得可以去看看C++基本编程之类的书好好恶补一下

第一最普通的情况下C++代码没有使用#pragma pack(n)改变边界对齐这里C#可以使用两种方法处理LayoutKindExplicit 和

LayoutKindSequential建议使用后者虽然前者是万金油不过使用起来太累有爱出错

C++:

structTest

{

inttest;

chartest;

__inttest;

shorttest;

};

Test*__stdcallGetTest()

{

testtest=;

testtest=;

testtest=;

testtest=;

return&test;

}

C#(这里有两种方案使用LayoutKindExplicit 和LayoutKindSequential注意一下)

[StructLayout(LayoutKindExplicit)]

publicstructTest

{

[FieldOffset()]

publicinttest;

[FieldOffset()]

publicchartest;

[FieldOffset()]

publicInttest;

[FieldOffset()]

publicshorttest;

}

[StructLayout(LayoutKindSequential)]

publicstructTest

{

publicinttest;

publicchartest;

publicInttest;

publicshorttest;

}

[DllImport(TestDll)]

publicstaticexternIntPtrGetTest();

//#################################

IntPtrp=GetTest();

Testtest=(Test)MarshalPtrToStructure(ptypeof(Test));

ConsoleWriteLine(testtest+testtest+testtest+testtest);

IntPtrp=GetTest();//Autopack

Testtest=(Test)MarshalPtrToStructure(ptypeof(Test));

ConsoleWriteLine(testtest+testtest+testtest+testtest);

第二特殊的情况下代码使用#pragma pack(n)改变了边界对齐这里要使用要使用 [StructLayout(LayoutKindSequential Pack = N)] 对齐否则出错

C++:

#pragmapack()

structTest

{

inttest;

chartest;

__inttest;

shorttest;

};

#pragmapack()

#pragmapack()

structTest

{

inttest;

chartest;

__inttest;

shorttest;

};

#pragmapack()

#pragmapack()

structTest

{

inttest;

chartest;

__inttest;

shorttest;

};

#pragmapack()

C#:

[StructLayout(LayoutKindSequentialPack=)]

structTest

{

publicinttest;

publicchartest;

publicInttest;

publicshorttest;

}

[StructLayout(LayoutKindSequentialPack=)]

structTest

{

publicinttest;

publicchartest;

publicInttest;

publicshorttest;

}

[StructLayout(LayoutKindSequentialPack=)]

structTest

{

publicinttest;

publicchartest;

publicInttest;

publicshorttest;

}

[DllImport(TestDll)]

publicstaticexternIntPtrGetTest();

[DllImport(TestDll)]

publicstaticexternIntPtrGetTest();

[DllImport(TestDll)]

publicstaticexternIntPtrGetTest();

//#################################

IntPtrp=GetTest();//pack

Testtest=(Test)MarshalPtrToStructure(ptypeof(Test));

IntPtrp=GetTest();//pack

Testtest=(Test)MarshalPtrToStructure(ptypeof(Test));

IntPtrp=GetTest();//pack

Testtest=(Test)MarshalPtrToStructure(ptypeof(Test));

ConsoleWriteLine(testtest+testtest+testtest+testtest);

ConsoleWriteLine(testtest+testtest+testtest+testtest);

ConsoleWriteLine(testtest+testtest+testtest+testtest);

最后总结一下LayoutKind有个枚举值LayoutKindAuto LayoutKindExplicit 和LayoutKindSequentialLayoutKindAuto或者为使用LayoutKind属性的结构体

进行PINVOKE调用会抛出异常改类型不允许进行PINVOKE调用LayoutKindSequential在中顺序布局一般情况(上面两种)推荐用这个LayoutKindExplicit

只推荐特殊情况使用因为他会明确指定成员的内存offset很强大也很繁琐

上一篇:当DataSet中包含主/子表时,Update更新步骤

下一篇:套接字编程介绍