CommandLineToArgvW
至少有三个你必须注意的怪癖:
The result is an array of pointers to wide-character strings.
The MASM32 function crt_printf
uses the function printf
from the Microsoft VC runtime library (msvcrt.dll). Therefore, you can use an uppercase 'S' as the type field character. Take a look at printf
Type Field Characters on MSDN.
The result is the address of the first element of an array of pointers to a string.
Most print functions expect a pointer to a string, not a pointer to a pointer to a string. You have to dereference that address to get a pointer to the string. A command line "Hello.exe I am Hello" will be splitted into four strings: "Hello.exe", "I", "am", "Hello". The pointers to these strings are to find in an array with 4 pointers: [pointer to "Hello.exe"], [pointer to "I"], and so on. Assume the function CommandLineToArgvW
has a return value EAX=0x001445A8. The Hexdump looks like
Address Hex dump ASCII
001445A8 B8 45 14 00|CC 45 14 00|D0 45 14 00|D6 45 14 00| ¸E.ÌE.ÐE.ÖE.
001445B8 48 00 65 00|6C 00 6C 00|6F 00 2E 00|65 00 78 00| H.e.l.l.o...e.x.
001445C8 65 00 00 00|49 00 00 00|61 00 6D 00|00 00 48 00| e...I...a.m...H.
001445D8 65 00 6C 00|6C 00 6F 00|00 00 00 00|00 00 00 00| e.l.l.o.........
At address 0x001445A8 is a pointer to 0x001445B8 (displayed in the dump in little endian format) and this is the beginning of "Hello.exe" in wide-character format. The next pointer is 4 bytes behind 0x001445A8: 0x001445CC - points to "I". The next pointer is 4 bytes away and so on. You can quickly go through that array just by adding 4. And you can easily get the address of a string in the middle of the list by multiplying the index by 4 - the pointer to the third string ("am", index: 2) is at 0x001445A8 + 2 * 4 = 0x001445B0 => 0x001445D0 => "am".
The function allocates memory, which has to be manually freed with LocalFree
.
我尽可能少地更改了您的程序:
include \masm32\include\masm32rt.inc
.data
Format db "argc: %d", 10, 0
fmt db "%S",10,0
szArglist dd ?
.code
start:
push ebp
mov ebp, esp
sub esp, 4
call GetCommandLineW
lea ecx, dword ptr[ebp - 4]
push ecx
push eax
call CommandLineToArgvW
mov [szArglist], eax
mov esi, eax
mov ebx, [ebp-4]
@@:
push dword ptr [esi]
push OFFSET fmt
call crt_printf
add esp, 8
add esi, 4
dec ebx
jne @B
push dword ptr [szArglist]
call LocalFree
push dword ptr [ebp - 4]
push offset Format
call crt_printf
add esp, 8
push 0
call ExitProcess
end start
MASM32函数StdOut
无法处理宽字符字符串。您需要先将其转换为ANSI字符串。为此目的的Windows函数是WideCharToMultiByte
:
include \masm32\include\masm32rt.inc
.data
szArglist dd ?
buf db 1024 DUP (?)
crlf db 13, 10, 0
.code
start:
push ebp
mov ebp, esp
sub esp, 4
call GetCommandLineW
lea ecx, dword ptr[ebp - 4]
push ecx
push eax
call CommandLineToArgvW
mov [szArglist], eax
mov esi, eax
mov ebx, [ebp-4]
@@:
push NULL
push NULL
push SIZEOF buf
push OFFSET buf
push -1
push [esi]
push 0
push 0
call WideCharToMultiByte
push OFFSET buf
call StdOut
push OFFSET crlf
call StdOut
add esi, 4
dec ebx
jne @B
push dword ptr [szArglist]
call LocalFree
push OFFSET buf
push dword ptr [ebp - 4]
call dwtoa
push OFFSET buf
call StdOut
push OFFSET crlf
call StdOut
push 0
call ExitProcess
end start
szArglist
是一个指向字符串的指针数组。只要你不用LocalFree
销毁它们,它们就会一直保存下去。进一步处理——比如与常量字符串进行比较——并不像高级编程语言那样容易,并且你不需要将它们传输到“变量”中。根据你的意图,方法是完全不同的。如果你能更详细地描述你的意图,我很乐意给你展示一个例子。 - rkhb