WIN64 下的 NetWkstaGetInfo ACCESS_VIOLATION
NetWkstaGetInfo ACCESS_VIOLATION under WIN64
我有代码,多年来在 WIN32 下运行良好。但是昨天,在 WIN64 下编译后,我在尝试获取 wki100_langroup 字段时遇到了奇怪的 ACCESS_VIOLATION 错误。这段代码哪里错了? (计算机不在域和 Delphi 11 调试 window 我可以看到,这个字段是空的)
const
NERR_SUCCESS = 0;
type
WKSTA_INFO_100 = record
wki100_platform_id: DWORD;
wki100_computername: LPWSTR;
wki100_langroup: LPWSTR;
wki100_ver_major: DWORD;
wki100_ver_minor: DWORD;
end;
LPWKSTA_INFO_100 = ^WKSTA_INFO_100;
function NetWkstaGetInfo(ServerName: LPWSTR; Level: DWORD; var BufPtr: Pointer): DWORD; stdcall;
external 'netapi32.dll' Name 'NetWkstaGetInfo';
function GetDomain: string;
var
PBuf: Pointer;
Res: Integer;
begin
Result := '';
Res := NetWkstaGetInfo(nil, 100, PBuf);
if (Res = NERR_Success) then begin
Result := LPWKSTA_INFO_100(PBuf)^.wki100_langroup; // ACCESS_VIOLATION here
if Assigned(PBuf) then
NetApiBufferFree(PBuf);
end;
end;
更新:
将指针更改为 PByte 后,我有同样的异常
function NetWkstaGetInfo(ServerName: LPWSTR; Level: DWORD; BufPtr: PByte): DWORD; stdcall;
external 'netapi32.dll' Name 'NetWkstaGetInfo';
function GetDomain: string;
var
PBuf: PByte;
Res: Integer;
begin
Result := '';
Res := NetWkstaGetInfo(nil, 100, @PBuf);
if (Res = NERR_Success) then begin
Result := LPWKSTA_INFO_100(PBuf)^.wki100_langroup; // ACCESS_VIOLATION here
if Assigned(PBuf) then
NetApiBufferFree(PBuf);
end;
end;
来自 Win32 的屏幕截图:
和Win64断点:
症状表明某些其他代码更改了 WKSTA_INFO_100
记录类型的默认记录对齐方式。
在 32 位编译器下不会产生影响,因为记录中的所有值也是 32 位的,因此即使指定了其他对齐大小,它们也会正确对齐。
在 64 位编译器下 DWORD
是 32 位的,而 LPWSTR 是 64 位的。默认 8 字节对齐,这意味着将在 wki100_platform_id
之后插入 4 个填充字节。如果使用其他对齐方式,以下字段将不会位于正确的位置。
要更正此问题,您需要在类型声明之前指定 8 字节对齐 {$A8}
。
type
{$A8}
WKSTA_INFO_100 = record
wki100_platform_id: DWORD;
wki100_computername: LPWSTR;
wki100_langroup: LPWSTR;
wki100_ver_major: DWORD;
wki100_ver_minor: DWORD;
end;
我有代码,多年来在 WIN32 下运行良好。但是昨天,在 WIN64 下编译后,我在尝试获取 wki100_langroup 字段时遇到了奇怪的 ACCESS_VIOLATION 错误。这段代码哪里错了? (计算机不在域和 Delphi 11 调试 window 我可以看到,这个字段是空的)
const
NERR_SUCCESS = 0;
type
WKSTA_INFO_100 = record
wki100_platform_id: DWORD;
wki100_computername: LPWSTR;
wki100_langroup: LPWSTR;
wki100_ver_major: DWORD;
wki100_ver_minor: DWORD;
end;
LPWKSTA_INFO_100 = ^WKSTA_INFO_100;
function NetWkstaGetInfo(ServerName: LPWSTR; Level: DWORD; var BufPtr: Pointer): DWORD; stdcall;
external 'netapi32.dll' Name 'NetWkstaGetInfo';
function GetDomain: string;
var
PBuf: Pointer;
Res: Integer;
begin
Result := '';
Res := NetWkstaGetInfo(nil, 100, PBuf);
if (Res = NERR_Success) then begin
Result := LPWKSTA_INFO_100(PBuf)^.wki100_langroup; // ACCESS_VIOLATION here
if Assigned(PBuf) then
NetApiBufferFree(PBuf);
end;
end;
更新: 将指针更改为 PByte 后,我有同样的异常
function NetWkstaGetInfo(ServerName: LPWSTR; Level: DWORD; BufPtr: PByte): DWORD; stdcall;
external 'netapi32.dll' Name 'NetWkstaGetInfo';
function GetDomain: string;
var
PBuf: PByte;
Res: Integer;
begin
Result := '';
Res := NetWkstaGetInfo(nil, 100, @PBuf);
if (Res = NERR_Success) then begin
Result := LPWKSTA_INFO_100(PBuf)^.wki100_langroup; // ACCESS_VIOLATION here
if Assigned(PBuf) then
NetApiBufferFree(PBuf);
end;
end;
来自 Win32 的屏幕截图:
和Win64断点:
症状表明某些其他代码更改了 WKSTA_INFO_100
记录类型的默认记录对齐方式。
在 32 位编译器下不会产生影响,因为记录中的所有值也是 32 位的,因此即使指定了其他对齐大小,它们也会正确对齐。
在 64 位编译器下 DWORD
是 32 位的,而 LPWSTR 是 64 位的。默认 8 字节对齐,这意味着将在 wki100_platform_id
之后插入 4 个填充字节。如果使用其他对齐方式,以下字段将不会位于正确的位置。
要更正此问题,您需要在类型声明之前指定 8 字节对齐 {$A8}
。
type
{$A8}
WKSTA_INFO_100 = record
wki100_platform_id: DWORD;
wki100_computername: LPWSTR;
wki100_langroup: LPWSTR;
wki100_ver_major: DWORD;
wki100_ver_minor: DWORD;
end;