C语言里面 提供了一些宏 可以使用变长参数
int MsgPrintf(INT dwszBuffer,TCHAR* szCaption,TCHAR* szFormat,...)
{
LPVOID lpszBuffer;
va_list pArgList;
va_start(pArgList,szFormat);
lpszBuffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,100);
_vsntprintf((LPTSTR)lpszBuffer,dwszBuffer/sizeof (TCHAR),szFormat,pArgList);
va_end(pArgList);
return MessageBox(NULL,(LPTSTR)lpszBuffer,szCaption,MB_OK);
}
如果要知道变长参数的长度 就不得不在传一个参数来进行标识了
因为是C语言调用方式,所以栈由调用者来平衡 也就是add esp,xxh 这个xxx也就是参数的总长度
add esp,xxh会被解释成 83h 4ch xxh 也就是函数返回地址 加上2 就是参数的总字节数了
C语言测试代码如下
int Test(int a,int b,...)
{
int dwSizeOfPar;
int *p = &a;
dwSizeOfPar = *((int *)*(p - 1));
dwSizeOfPar = ((dwSizeOfPar >> 16) & 0x0FF) >> 2;
return dwSizeOfPar;
}
根据这个原理 写了一个 Win32ASM版本的格式化输出
_MsgBoxPrintf proc C _dwSizeOfBuff:DWORD,_lpszCaption:DWORD,_lpszFormat:DWORD,_varg:VARARG
LOCAL @hProcessHeap:DWORD
LOCAL @lpszBuffer:DWORD
LOCAL @dwSizePar:DWORD
lea eax,_dwSizeOfBuff
mov eax,[eax - 4] ;获取函数的返回地址
movzx eax,byte ptr [eax + 2] ;获取参数总字节数
shr eax,2 ;获取参数个数
;没有传递不定参数,作为默认处理
cmp eax,3
jnb @F
sub eax,3
mov @dwSizePar,eax
invoke GetProcessHeap
mov @hProcessHeap,eax
invoke HeapAlloc,@hProcessHeap,HEAP_ZERO_MEMORY,_dwSizeOfBuff
mov @lpszBuffer,eax
.while @dwSizePar
lea esi,_varg
mov ebx,@dwSizePar
sub ebx,1
mov eax,[esi + ebx * 4]
push eax
dec @dwSizePar
.endw
push _lpszFormat
push @lpszBuffer
call wsprintf
invoke MessageBox,NULL,@lpszBuffer,_lpszCaption,MB_OK
ret
@@:
invoke MessageBox,NULL,_lpszFormat,_lpszCaption,MB_OK
ret
_MsgBoxPrintf endp