我们有一个PInvoke如下:
[DllImport(DllName, EntryPoint = "ExternalName", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr ExternalFunction(IntPtr state, IntPtr inputData, int inputIndex, int inputLength, int tailLength);
使用C
声明如下:
void * __cdecl ExernalName(void* state, void* inputData, int32_t inputIndex, int32_t inputLength, int32_t tailLength);
当以x86运行.NET应用程序时,它可以正常工作。但是,当在x64机器上的AnyCPU中运行时,函数参数的内存地址关闭。
例如,假设state = 1,inputData = 2,inputIndex = 3,inputLength = 4.State和InputData都是void *,因此它们应该是8个字节长,而其余的应该是4个字节。 / p>
如果我在函数中设置断点,则值为state为2.假设状态的内存地址确定为0x00000008。
inputData的内存地址返回0x0000000C,inputIndex返回0x00000010,inputLength返回0x00000014。
第一个问题,为什么inputData后的4个字节的内存地址和inputData后的inputIndex 4个字节?不应该将state和inputData分别为8个字节吗?
第二个问题,如果我实际检查值应该的位置的内存地址,它们就在那里,但是哪里是1? 1位于0x00000000。
这怎么会发生?我的错误假设是什么?我做错了什么?
答案 0 :(得分:1)
这是由x64模式下的调用约定引起的。实际上,在x64中没有cdecl,没有stdcall,没有fastcall - 这些指令被忽略。
在Windows中,x64模式中只有一个调用约定 - Microsoft x64调用约定。在此约定中,如果每个参数的大小为1,2,4或8个字节,则前四个参数将在寄存器中传递,而不是通过堆栈传递。同时,保留32个字节用于调试目的。
这意味着获取输入参数的地址并直接从堆栈读取其值是没有意义的。
尝试在控制台上打印值,而不是在调试器中查看其值。还要检查可能强制使用cdecl而不是默认x64调用约定的编译器选项。