Windows 64位平台调用EnumFontFamiliesEx枚举字体出现访问冲突如何解决
问题原因
报错是64位环境下回调函数签名不匹配导致的,32位下可以正常运行属于巧合兼容:
EnumFontFamiliesEx要求的回调函数前两个参数是结构体指针,你代码里用var引用传递,32位下引用的底层实现和指针刚好兼容,64位下调用约定导致参数地址错位- 回调函数第四个参数是
LPARAM类型,你定义成Pointer在部分场景下也会触发长度不匹配 - 你把
ListBox1.Items(实际为TStrings子类)强制转换为TStringList存在类型不匹配风险
修复代码
只需要修改回调函数的定义即可:
procedure TForm1.Button1Click(Sender: TObject); // 修正回调函数签名:参数用指针、返回值用BOOL、第四个参数类型为LPARAM function EnumFontFamExProc(LogFont: PEnumLogFontEx; TextMetric: PNewTextMetric; FontType: Integer; Data: LPARAM): BOOL; stdcall; var Strings: TStrings; TempFaceName: String; FontTypeObject: TFontTypeObject; begin Strings := TStrings(Data); TempFaceName := LogFont.elfLogFont.lfFaceName; if (Strings.IndexOf(TempFaceName) = -1) then begin FontTypeObject:= TFontTypeObject.Create; FontTypeObject.FtoFontType:= FontType; FontTypeObject.FtoFlags:= TextMetric.ntmFlags; Strings.AddObject(TempFaceName, FontTypeObject); end; Result := True; end; var DC: HDC; LogFont: TLogFont; begin DC:= GetDC(0); try FillChar(LogFont, SizeOf(LogFont), 0); LogFont.lfCharSet:= DEFAULT_CHARSET; LogFont.lfFaceName:= ''; LogFont.lfPitchAndFamily:= 0; EnumFontFamiliesEx(DC, LogFont, @EnumFontFamExProc, LPARAM(ListBox1.Items), 0); ListBox1.Sorted:= TRUE; finally ReleaseDC(0, DC); end; end;
补充说明
32位下没有触发报错是因为32位stdcall约定的参数传递规则、栈对齐逻辑刚好掩盖了签名不匹配的问题,64位下微软x64调用约定对参数长度、传递方式的校验更严格,不匹配的签名会直接触发访问冲突。
内容的提问来源于stack exchange,提问作者Willer
相关产品推荐
相关产品推荐

