【问题标题】:Impossible to print FindFirstFile WIN32_FIND_DATA structure properties with MASM无法使用 MASM 打印 FindFirstFile WIN32_FIND_DATA 结构属性
【发布时间】:2013-03-14 23:48:13
【问题描述】:

我想在 MASM 中重现 C++ 代码的行为:

C++ 代码:

#include <Windows.h>
#include <iostream>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>

int                     _tmain(int ac, TCHAR **av)
{
    HANDLE              hFile;
    WIN32_FIND_DATA     findFileData;
    BOOL                retFindNextFile;

    if ((hFile = FindFirstFile(TEXT("C:\\Users\\Bloodsucker94\\Desktop\\TestFolder\\*.txt"), &findFileData)) == INVALID_HANDLE_VALUE)
    else {
        do {
            _tprintf(TEXT("%s\n"), findFileData.cFileName);
            retFindNextFile = FindNextFile(hFile, &findFileData);

        } while (retFindNextFile == TRUE);
    }
    getchar();
    return (EXIT_SUCCESS);
}

还有 MASM 代码:

.386
.model                          flat, stdcall
option                          casemap :none

include                         \masm32\include\windows.inc
include                         \masm32\include\kernel32.inc
include                         \masm32\include\masm32.inc
include                         \masm32\include\masm32rt.inc
includelib                      \masm32\lib\kernel32.lib
includelib                      \masm32\lib\masm32.lib
include                         \masm32\include\msvcrt.inc
includelib                      \masm32\lib\msvcrt.lib

.data

FolderPath                      BYTE                        "C:\Users\Bloodsucker94\Desktop\TestASM\*.txt", 0
FindFirstFileError              BYTE                        "FindFirstFile() failed with code %d", 0
FindFirstFileSuccess            BYTE                        "First file found with success - hfile=%d", 0
PrintStructAddr                 BYTE                        "addr=Ox%08X", 0
PrintFileName                   BYTE                        "%s", 0

.data?

hFile                           HANDLE                      ?
findFileData                    WIN32_FIND_DATA             <>
retFindNextFile                 BOOL                        ?
ErrorCode                       DWORD                       ?

.code
start:

    ;--------------------------------------------------------

    invoke  FindFirstFile,      ADDR FolderPath,            \
                                ADDR findFileData

    mov     hFile,              eax

    .IF hFile == INVALID_HANDLE_VALUE
        invoke  GetLastError
        mov     ErrorCode,      eax
        invoke  crt_printf,     ADDR FindFirstFileError,    \
                                ErrorCode
        jmp                     _quit                                
    .ENDIF

    ;--------------------------------------------------------

    mov     ebx,                OFFSET findFileData
    mov     al,                 [ebx].WIN32_FIND_DATA.cFileName

    print   str$(findFileData.cFileName)
    ;print  str$([ebx].WIN32_FIND_DATA.cFileName)
    ;print  str$(al)

    ;INVOKE crt_printf,         ADDR PrintFileName,         \
    ;                           findFileData.cFileName

    ;--------------------------------------------------------

_quit:
    invoke  ExitProcess,        0

end start

目前,如您所见,我只想打印目录“TestASM”中的第一个文件名。在执行时 FindFirstFile() 似乎执行得很好,并且 hFile 句柄似乎也是正确的。但是我不明白为什么我所有的打印调用都会导致一个显示错误消息的消息框。我认为这是一个分段错误。但我尊重 C++ 代码行为。我尝试了几种代码组合都没有结果。

有人可以帮我吗?

【问题讨论】:

  • 我尝试了一种奇怪的体验。我用窗口日志(MessageBox)替换我的控制台日志,它可以工作。为什么我的控制台日志失败?但是,它是相同的数据!

标签: assembly masm cpu-registers


【解决方案1】:

你应该声明printf PROTO C :VARARG;

【讨论】:

  • 函数已定义:错误 A2005:符号重新定义:printf。 crt_printf 也一样
  • 也许问题是 cFileName 是 TCHAR* 类型,而 printf 在 C++ 中可以正确使用该类型。然而,好的功能是_tprintf。但是我在 MASM 中没有找到这个函数的等价物。你有想法吗 ?再次感谢
  • 作为调试提示,您可以更改代码以打印一些整数而不是字符串
  • 是的原生类型(int、char*、double 等)可以完美运行。只是 Windows 类型(此处为 TCHAR*)不起作用。我需要一个特殊的函数来打印像 TCHAR* 这样的 Windows 类型。在我的 C++ 代码中,我使用 _tprintf。如果我使用简单的 printf 打印的结果不正确。 MessageBox 打印效果很好,因为它集成了一个特殊的 Windows API 函数。感谢您的帮助。
  • 只是为了确保:您说如果您在代码中使用 printf(我的意思是 C++ 代码)打印结果会混乱?
【解决方案2】:

我用窗口日志 (MessageBox) 替换了我的控制台日志,它可以工作。为什么我的控制台日志失败?但是,它是相同的数据!


您错误地使用了str$。如果您查看它的定义 (masm32\macros\macros.asm),您会发现它的作用是采用 DWORD 大小的整数,然后使用创建该整数的字符串表示形式(例如 123 -> "123") dwtoa,并返回字符串的地址。

由于您尝试打​​印已经是字符串的内容,因此正确的方法是:

print   ADDR findFileData.cFileName


至于您看到的崩溃 - 您当前的代码 (print str$(findFileData.cFileName)) 会发生什么,str$ 将执行以下操作:

invoke dwtoa,findFileData.cFileName,ADDR rvstring

当 MASM 扩展此 invoke 宏并且在参数前面没有找到 ADDR 运算符时,它将按值传递该参数。在这种情况下,它将假定您尝试传递findFileData.cFileName 的第一个元素,即BYTE(或WORD,如果您使用的是宽字符串版本)。
所以实际上,这就是实际将作为第一个参数压入堆栈的内容:

mov al,findFileData.cFileName  ; al is set to the first character in the string
movzx ax,al
push ax   ; can't push bytes on x86 so the byte is extended to a word

由于dwtoa 期望DWORD 作为第一个参数,而您传递的是WORD,当您从dwtoa 返回时,您将得到一个不平衡的堆栈,这可能导致各种不良行为(在这种情况是崩溃)。

【讨论】:

    【解决方案3】:

    这没问题。

    mov     ebx,                OFFSET findFileData
    lea     eax,                 [ebx].WIN32_FIND_DATA.cFileName
    
    print   eax 
    

    也是这样:

    INVOKE crt_printf,         ADDR PrintFileName,         \
                               offset findFileData.cFileName
    

    看到此代码与您的代码之间的区别了吗?您需要传递字符串的地址。我们使用lea 对第一个进行此操作,并为printf 使用偏移量

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-29
      • 1970-01-01
      • 2019-05-28
      相关资源
      最近更新 更多