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

Delphi中如何正确为FormatMessage传递array of const参数?

解决Delphi中FormatMessage传递array of const的问题

问题根源

Windows API的FormatMessage在使用FORMAT_MESSAGE_ARGUMENT_ARRAY标志时,要求传入的是**DWORD_PTR(对应Delphi的NativeUInt)类型的数组指针**,每个元素对应格式化字符串中的一个占位符。而Delphi的array of const本质是TVarRec数组,TVarRec是包含类型标识和值的变体结构,直接传递或仅提取部分字段都会导致类型不匹配,引发访问冲突或乱码。

错误代码分析

第一段代码问题

直接传递@Args[0]给Arguments参数,相当于把TVarRec数组的指针传给了期望DWORD_PTR数组的API。TVarRec的结构是VType(2字节)+ 联合值(4/8字节),和API要求的纯数值数组结构完全不符,必然触发访问冲突。

第二段代码问题

仅提取TVarRec.VPointer,忽略了vtInteger、vtBoolean等类型的VInteger字段,且未将值转换为DWORD_PTR类型,导致传入的参数值不符合API预期,出现乱码。

正确实现

需要遍历TVarRec数组,根据不同类型提取对应的值并转换为NativeUInt(匹配DWORD_PTR),构建符合API要求的参数数组后再调用FormatMessage:

function FormatMessageFromString(const AFormat: string; const Args: array of const): string;
var
  Buffer: PChar;
  ArgArray: array of NativeUInt;
  I: Integer;
begin
  // 构建符合FormatMessage要求的DWORD_PTR数组
  SetLength(ArgArray, Length(Args));
  for I := Low(Args) to High(Args) do
  begin
    case Args[I].VType of
      vtInteger: ArgArray[I] := NativeUInt(Args[I].VInteger);
      vtBoolean: ArgArray[I] := NativeUInt(Byte(Args[I].VBoolean));
      vtChar: ArgArray[I] := NativeUInt(Args[I].VChar);
      vtExtended: ArgArray[I] := NativeUInt(@Args[I].VExtended^); // 浮点数需传指针
      vtString: ArgArray[I] := NativeUInt(PChar(Args[I].VString^));
      vtPChar: ArgArray[I] := NativeUInt(Args[I].VPChar);
      vtAnsiString: ArgArray[I] := NativeUInt(PAnsiChar(Args[I].VAnsiString^));
      vtWideChar: ArgArray[I] := NativeUInt(Args[I].VWideChar);
      vtWideString: ArgArray[I] := NativeUInt(PWideChar(Args[I].VWideString^));
      vtUnicodeString: ArgArray[I] := NativeUInt(PWideChar(Args[I].VUnicodeString^));
      else
        raise Exception.CreateFmt('Unsupported argument type: %d', [Args[I].VType]);
    end;
  end;

  if FormatMessage(
    FORMAT_MESSAGE_FROM_STRING or FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_ARGUMENT_ARRAY,
    PWideChar(AFormat),
    0,
    0,
    @Buffer,
    0,
    @ArgArray[0]) <> 0 then
  try
    Result := Buffer;
    // 替换换行符为Windows标准格式
    Result := StringReplace(Result, #10, #13#10, [rfReplaceAll]);
  finally
    LocalFree(HLOCAL(Buffer));
  end
  else
    RaiseLastOSError;
end;

关键说明

  • 类型转换:针对每种TVarRec类型,将值转换为NativeUInt(32位系统为Cardinal,64位为UInt64),匹配DWORD_PTR的定义。
  • 浮点数处理:FormatMessage要求浮点数参数传递指针,因此需要传入VExtended的地址。
  • 字符串类型:不同Delphi字符串类型(Ansi、Wide、Unicode)需转换为对应的C风格字符串指针后传入。
  • 换行符处理:FormatMessage默认输出\n(LF),替换为Windows标准的\r\n(CRLF)提升兼容性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 22:45:24