You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB6调用Windows DLL转PHP FFI遇参数兼容问题求助

问题:VB6调用UNZDLL32.DLL转PHP FFI实现遇到参数不兼容错误

原VB6可运行代码(用于调用UNZDLL32.DLL处理地址):

Public Declare Function UNZ_INIT_EX Lib "UNZDLL32.DLL" () As Long
Public Declare Function UNZ_TERM Lib "UNZDLL32.DLL" (ByVal hUnz As Long) As Long
Public Declare Function UNZ_CHECKADDRESS Lib "UNZDLL32.DLL" (ByVal hUnz As Long, ByVal Line1$, ByVal Line2$, ByVal Line3$, ByVal Line4$) As Long
Public Declare Function UNZ_GETSTDADDRESS Lib "UNZDLL32.DLL" (ByVal hUnz As Long, ByVal szFirmName As String, ByVal szPRUrb As String, ByVal szDelLine As String, ByVal szLastLine As String) As Long

Dim hUnz As Long
Dim szFirmName As String * 51      ' ** 所有固定长度字符串默认设为51位
Dim szPRUrb As String * 51
Dim szDelLine As String * 51
Dim szLastLine As String * 51
Dim szCity As String * 51
Dim szState As String * 51
Dim szZIP As String * 51
Dim result As Long
Dim Line1 As String, Line2 As String, Line3 As String, Line4 As String
Dim retAry(0 To 34) As String

hUnz = UNZ_INIT_EX() '成功返回1,失败返回0
result = UNZ_TERM(hUnz) '成功返回1

Line1 = ""          ' 无公司名称
Line2 = ""          ' 此地址不含波多黎各地址信息
Line3 = "1234 Main St"  ' 街道地址
Line4 = "Some City, ST 12345"    ' 拼接城市-州-ZIP

result = UNZ_CHECKADDRESS(hUnz, Line1, Line2, Line3, Line4)
retAry(8) = CStr(result) '错误码转为字符串

result = UNZ_GETSTDADDRESS(hUnz, szFirmName, szPRUrb, szDelLine, szLastLine)
retAry(1)  = FixedToVar(szDelLine) '标准化街道地址
retAry(29) = FixedToVar(szFirmName)
retAry(30) = FixedToVar(szPRUrb)
retAry(2)  = FixedToVar(szLastLine) '标准化城市-州-ZIP

尝试编写的PHP FFI代码:

$ffi = FFI::cdef(
    "int32_t UNZ_INIT_EX();
     long int UNZ_CHECKADDRESS(int32_t*, char *str, char *str, char *str, char *str);
     long int UNZ_GETSTDADDRESS(int32_t);
     long int UNZ_TERM(int32_t*);
     long int UNZ_ERROR();",
   "C:\Windows\SysWOW64\unzdll64.dll");
$hunz = $ffi->UNZ_INIT_EX();
echo "hunz: $hunz";

调用$term = $ffi->UNZ_TERM($hunz);时触发错误:

Fatal error: Uncaught FFI\Exception: Passing incompatible argument 1 of C function 'UNZ_TERM', expecting 'int32_t*', found PHP 'int' ...

调用UNZ_CHECKADDRESS时也出现相同错误,需指导如何正确定义int32_t及字符串引用的FFI字段。


解答

核心错误原因

你的PHP FFI函数声明存在两个关键问题:

  1. 句柄参数类型错误:VB6中ByVal hUnz As Long是传值的32位整数,对应C的int32_t,而非指针int32_t*。你错误地将UNZ_TERM、UNZ_CHECKADDRESS的第一个参数声明为指针类型,导致参数不兼容。
  2. 输出字符串参数缺失:UNZ_GETSTDADDRESS需要传入固定长度的缓冲区来接收返回值,你之前的声明完全遗漏了这些参数。

正确的PHP FFI实现代码

<?php
// 匹配VB6参数定义的正确函数声明
$ffi = FFI::cdef(
    "int32_t UNZ_INIT_EX();
     int32_t UNZ_TERM(int32_t hUnz);
     int32_t UNZ_CHECKADDRESS(int32_t hUnz, char* line1, char* line2, char* line3, char* line4);
     int32_t UNZ_GETSTDADDRESS(int32_t hUnz, char* szFirmName, char* szPRUrb, char* szDelLine, char* szLastLine);",
    "C:\\Windows\\SysWOW64\\unzdll32.dll" // VB6为32位环境,需对应使用32位DLL
);

// 初始化句柄
$hUnz = $ffi->UNZ_INIT_EX();
if ($hUnz === 0) {
    die("UNZ初始化失败");
}
echo "初始化成功,句柄:$hUnz\n";

// 准备输入地址的固定长度缓冲区(对应VB6的String*51)
$line1 = $ffi->new("char[51]");
$line2 = $ffi->new("char[51]");
$line3 = $ffi->new("char[51]");
$line4 = $ffi->new("char[51]");

// 填充输入地址内容
FFI::copy($line3, "1234 Main St");
FFI::copy($line4, "Some City, ST 12345");

// 调用地址检查函数
$result = $ffi->UNZ_CHECKADDRESS($hUnz, $line1, $line2, $line3, $line4);
echo "UNZ_CHECKADDRESS返回码:$result\n";

// 准备接收标准化地址的缓冲区
$szFirmName = $ffi->new("char[51]");
$szPRUrb = $ffi->new("char[51]");
$szDelLine = $ffi->new("char[51]");
$szLastLine = $ffi->new("char[51]");

// 调用获取标准化地址函数
$result = $ffi->UNZ_GETSTDADDRESS($hUnz, $szFirmName, $szPRUrb, $szDelLine, $szLastLine);
echo "UNZ_GETSTDADDRESS返回码:$result\n";

// 模拟VB6的FixedToVar函数:转换C风格固定长度字符串为PHP字符串
function fixedToVar($ffiStr) {
    global $ffi;
    $str = $ffi->string($ffiStr);
    return trim($str);
}

// 输出标准化地址结果
echo "标准化地址信息:\n";
echo "公司名称:" . fixedToVar($szFirmName) . "\n";
echo "PR地址:" . fixedToVar($szPRUrb) . "\n";
echo "街道地址:" . fixedToVar($szDelLine) . "\n";
echo "城市-州-ZIP:" . fixedToVar($szLastLine) . "\n";

// 释放句柄
$termResult = $ffi->UNZ_TERM($hUnz);
echo "句柄释放结果:$termResult\n";
?>

关键修正点说明

  • 句柄类型修正:所有接收hUnz的函数参数都改为int32_t(传值),而非指针,完全匹配VB6的ByVal hUnz As Long定义。
  • 字符串缓冲区处理:VB6的String*51对应PHP FFI中的char[51]数组,需用FFI::new分配内存,FFI::copy填充输入内容,FFI::string读取输出结果。
  • DLL版本匹配:VB6是32位环境,需使用unzdll32.dll而非unzdll64.dll(确保你的PHP也是32位版本,否则会出现兼容性问题)。
  • 字符串转换:通过自定义fixedToVar函数去除固定长度字符串末尾的空字符和多余空格,还原VB6的转换逻辑。

内容的提问来源于stack exchange,提问作者Landrew

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 12:49:58