解决方案 »

  1.   

    随C(++)编译器 版本不同,struct 可能是字节对齐的,也可能没有对齐(也可能在“项目”中设置)
    所以,对应的delphi record,你试试加上 packed 
      

  2.   

    这些都试了,包括强制字节对齐(从1到16),还是不行。
    如果返回的结构体是8字节就有问题,如果不是8字节就没有问题(比如删除或添加一个成员,或修改原有成员的类型)。现在看来,是Delphi和C在这方面的处理方式不同,从压栈的数据来看,返回值的地址会被压在栈顶,在C里面却把栈顶当做第一个参数,而不当作返回值,举个例子:
    Delphi:
    procedure test2;
    var
      buf: uv_buf_t;
      s: PAnsiChar;
    begin
      s := 'abcde'+#0;
      Writeln('uv_buf_t大小:' + IntToStr(Sizeof(uv_buf_t)));
      Writeln('s的地址:' + IntToHex(Integer(@s), 8));
      Writeln('buf的地址:' + IntToHex(Integer(@buf), 8));  buf := uv_buf_init(s, 5);  Writeln('buf的值:len=' + IntToStr(buf.len) + '   base=' + buf.base);
    end;那么在C里跟踪调试,运行结果如下:
    按照从右到左的压栈顺序,先压右边的参数,如下的顺序:
    0x0012FF00  40 ff 12 00  @...  这是返回值的地址
    0x0012FF04  b4 9d 41 00  ??A.  这是参数base的值
    0x0012FF08  05 00 00 00  ....   这是参数len的值
    问题就在这里了,现在base指向了0x0012FF00 地址,即指向了返回值所在的栈,而len指向base数据存放的栈,即0x0012FF04,整好偏移了4个字节。不知道这是什么原因。
      

  3.   

    编译优化时delphi会根据结构的大小把返回值放到堆栈或是寄存器里,可能8字节就刚好放到寄存器里了(DX:AX)。
    还有windows下C函数用stdcall调用模式的也很多。
      

  4.   

    你把C代码用bcc编译再试试。
      

  5.   

    你也可以这样声明试试:
    uv_buf_init: procedure(base: PAnsiChar; len: Cardinal; var p: uv_buf_t); cdecl;
      

  6.   

    其实这是Delphi编译器和VS编译器造成的,其实只有返回值是8字节才有这样的问题,其它字节的话就不会有问题。如果返回值是8个字节,Delphi会把参数先压栈,然后把返回值的变量地址当作最后一个参数压栈,如果Dll也是Delphi写的话,那么在Dll里,Delphi会把栈顶的值当作返回值的地址,栈顶往下依次为参数,然后把结果写到返回值的地址里。但现在的Dll是C写的,C的处理方试为(针对返回值是8字节的),C会把栈顶往下依次当作参数,所以在C里面接收到参数会错位,因为Delphi传过来的栈顶是返回值的指针。那么C处理回返回值是把低4位放到EAX里,把高4位放到EDX里,Delphi里根本没有读取这两个寄存器,所以返回值也得不到。问题就是这样的,解决方法,在Delphi里嵌入汇编可以解决这样的问题。这个项目是VS的项目,不知道用BCC能不能编译,如果能编译的话,应该可,毕竟和Delphi同一个家族的产品,传参数的方式应该是一致的。这样肯定也是不行的,我最初就用这样的方法试过了,现在想想,也知道为什么不行了。
      

  7.   

    既然你确定了结构体是通过edx:eax返回的,那就可以在Delphi中返回int64/uint64:
    uv_buf_init: function(base: PAnsiChar; len: Cardinal): uint64; cdecl;
    然后:
    PUInt64(@buf)^ := uv_buf_init(s, 5);