Я пытаюсь отобразить диалог открытия файла, используя Win32 API и сборку x64. Для этого я сопоставляю распределение памяти ожидаемой структуры с распределением памяти структуры OPENFILENAMEA
(в commdlg.h
), но, похоже, я ошибаюсь на 4 байта, поскольку размер моей структуры составляет 140 байт. Функция CommDlgExtendedError()
не возвращает CDERR_STRUCTSIZE
(0x0001), если я вручную устанавливаю для параметра lStructSize
значение 136 или 152, но вместо этого возникает ошибка «Нарушение доступа к местоположению чтения 0x0000010000007FF7».
Я использую MASM (ml64.exe
) в Visual Studio 2022 Community и собираю под x64.
Вот структура, которую я пытаюсь сопоставить (lpEditInfo
и lpstrPrompt
опущены) из: https://learn.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamea
typedef struct tagOFNA {
DWORD lStructSize;
HWND hwndOwner;
HINSTANCE hInstance;
LPCSTR lpstrFilter;
LPSTR lpstrCustomFilter;
DWORD nMaxCustFilter;
DWORD nFilterIndex;
LPSTR lpstrFile;
DWORD nMaxFile;
LPSTR lpstrFileTitle;
DWORD nMaxFileTitle;
LPCSTR lpstrInitialDir;
LPCSTR lpstrTitle;
DWORD Flags;
WORD nFileOffset;
WORD nFileExtension;
LPCSTR lpstrDefExt;
LPARAM lCustData;
LPOFNHOOKPROC lpfnHook;
LPCSTR lpTemplateName;
LPEDITMENU lpEditInfo;
LPCSTR lpstrPrompt;
void *pvReserved;
DWORD dwReserved;
DWORD FlagsEx;
} OPENFILENAMEA, *LPOPENFILENAMEA;
Вот мой код:
extrn ExitProcess: PROC
extrn GetOpenFileNameA: PROC
extrn CommDlgExtendedError: PROC
.data
filename db 256 dup(0)
tagOFNA STRUCT
lStructSize dd 0 ; 0 - dword
hwndOwner dq 0 ; 4 - qword
hInstance dq 0 ; 12 - qword
lpstrFilter dq 0 ; 20 - qword
lpstrCustomFilter dq 0 ; 28 - qword
nMaxCustFilter dd 0 ; 36 - dword
nFilterIndex dd 0 ; 40 - dword
lpstrFile dq offset filename ; 44 - qword
nMaxFile dd 256 ; 52 - dword
lpstrFileTitle dq 0 ; 56 - qword
nMaxFileTitle dd 0 ; 64 - dword
lpstrInitialDir dq 0 ; 68 - qword
lpstrTitle dq 0 ; 76 - qword
Flags dd 0 ; 84 - dword
nFileOffset dw 0 ; 88 - word
nFileExtension dw 0 ; 90 - word
lpstrDefExt dq 0 ; 92 - qword
lCustData dq 0 ; 100 - qword
lpfnHook dq 0 ; 108 - qword
lpTemplateName dq 0 ; 116 - qword
pvReserved dq 0 ; 124 - qword
dwReserved dd 0 ; 132 - dword
FlagsEx dd 0 ; 136 - dword
tagOFNA ENDS
myofn tagOFNA <sizeof tagOFNA>
.code
main PROC
sub rsp, 28h
lea rcx, myofn
call GetOpenFileNameA
call CommDlgExtendedError
mov rcx, rax
call ExitProcess
main ENDP
end
Я пытался установить параметры для структуры, но это не имело никакого значения, поэтому я попытался получить минимальный объем кода, чтобы просто открыть диалоговое окно, установив для каждого параметра значение null, кроме параметров структуры lStructSize
и lpstrFile
.
Как Питер прокомментировал, структура C имеет отступы для выравнивания. Вам не хватает 3 двойных слов, которые увеличивают размер от 140 до 152, как и ожидалось. Вы должны вставить дополнение после lStructSize
, nMaxFile
и nMaxFileTitle
, чтобы выровнять следующие элементы qword с числом, кратным 8:
lStructSize dd 0 ; 0 - dword
pad1 dd 0 ; 4 - dword
hwndOwner dq 0 ; 8 - qword
hInstance dq 0 ; 16 - qword
lpstrFilter dq 0 ; 24 - qword
lpstrCustomFilter dq 0 ; 32 - qword
nMaxCustFilter dd 0 ; 40 - dword
nFilterIndex dd 0 ; 44 - dword
lpstrFile dq offset filename ; 48 - qword
nMaxFile dd 256 ; 56 - dword
pad2 dd 0 ; 60 - dword
lpstrFileTitle dq 0 ; 64 - qword
nMaxFileTitle dd 0 ; 72 - dword
pad3 dd 0 ; 76 - dword
lpstrInitialDir dq 0 ; 80 - qword
lpstrTitle dq 0 ; 88 - qword
Flags dd 0 ; 96 - dword
nFileOffset dw 0 ; 100 - word
nFileExtension dw 0 ; 102 - word
lpstrDefExt dq 0 ; 104 - qword
lCustData dq 0 ; 112 - qword
lpfnHook dq 0 ; 120 - qword
lpTemplateName dq 0 ; 128 - qword
pvReserved dq 0 ; 136 - qword
dwReserved dd 0 ; 144 - dword
FlagsEx dd 0 ; 148 - dword
Кстати, ключевое слово MASM struct принимает параметр выравнивания. В этом случае это будет tagOFNA STRUCT 8
(то же самое, что компиляция с /Zp8
, за исключением того, что последний будет применяться по умолчанию ко всем структурам).
Было бы несколько необычно иметь смещенные qwords; Вы уверены, что после
DWORD lStructSize;
нет отступов, чтобы выровнять qwordHWND
и другие более поздние qwords, которые в вашем asm имеют нечетное число, кратное 8? (ИлиHWND
по-прежнему 32-битный в x64?) Вы можете посмотреть сгенерированный компилятором asm, чтобы проверить смещения структур и увидеть, где смещения элементов отличаются от вашего asm. (godbolt.org). например напишите функции, которые назначают несколько членов. Вы можете выполнить «двоичный поиск», чтобы найти первый элемент с неправильным смещением.