CRT WinAPI和可变参数printf函数

时间:2017-09-17 01:25:26

标签: unicode printf ascii messagebox crt

我目前正在研究WinAPI GUI(由Charles Petzold编写Windows第5版)和C(不是C ++)。我正在尝试并希望尽可能保持纯C,然后可能会跳转到C ++或C#。 我的问题依赖于使用可变参数***printf***()版本。

项目:我想创建一个能够识别我是使用ASCII,UNICODE还是其他类型的多字节字符集(MBCS)的函数,然后相应地格式化输入并在MessageBox()中键入输出。

在我正在阅读的书中,作者正在使用下面的源代码来制作类似的东西: SCRNSIZE.C

/*−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
SCRNSIZE.C −− Displays screen size in a message box
(c) Charles Petzold, 1998
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−*/
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
int CDECL MessageBoxPrintf (TCHAR * szCaption, TCHAR * szFormat, ...)
{
TCHAR szBuffer [1024] ;
va_list pArgList ;
// The va_start macro (defined in STDARG.H) is usually equivalent to:
// pArgList = (char *) &szFormat + sizeof (szFormat) ;
va_start (pArgList, szFormat) ;
// The last argument to wvsprintf points to the arguments
_vsntprintf (szBuffer, sizeof (szBuffer) / sizeof (TCHAR),
szFormat, pArgList) ;
// The va_end macro just zeroes out pArgList for no good reason
va_end (pArgList) ;
return MessageBox (NULL, szBuffer, szCaption, 0) ;
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
int cxScreen, cyScreen ;
cxScreen = GetSystemMetrics (SM_CXSCREEN) ;
cyScreen = GetSystemMetrics (SM_CYSCREEN) ;
MessageBoxPrintf (TEXT ("ScrnSize"),
TEXT ("The screen is %i pixels wide by %i pixels high."),
cxScreen, cyScreen) ;
return 0 ;
}

程序使用获得的信息以像素为单位显示视频显示的宽度和高度 来自GetSystemMetrics函数。 GetSystemMetrics是获取信息的有用功能 关于Windows中各种对象的大小。

根据我的理解,他正在使用TCHAR,以便他的功能可以处理UNICODE或ASCII。 TCHAR定义为:

#ifdef UNICODE
typedef WCHAR TCHAR, * PTCHAR ;
typedef LPWSTR LPTCH, PTCH, PTSTR, LPTSTR ;
typedef LPCWSTR LPCTSTR ;
#else
typedef char TCHAR, * PTCHAR ;
typedef LPSTR LPTCH, PTCH, PTSTR, LPTSTR ;
typedef LPCSTR LPCTSTR ;
#endif

虽然MessageBox()正在使用以下技巧来处理任一ASCII码UNICODE:

#ifdef UNICODE
#define MessageBox MessageBoxW
#else
#define MessageBox MessageBoxA
#endif

在尝试编码我的项目之前(我开始但我有些问题我自己无法回答)我想解决一些我还没想到的难题。

1)他如何在int中使用MessageBoxPrintf()作为返回类型,并且能够返回像MessageBox()这样的完整C对象?一般来说,我的返回类型应该是什么?当我返回像MessageBox()的完整函数?

2)作者使用的函数是_vsntprintf。MSDN否认它存在,但我在源代码中找到了这个:

#define _vsntprintf _vsnwprintf
int _vsnwprintf(wchar_t *_Buffer, size_t _BufferCount, const wchar_t *_Format, va_list _ArgList)

他还在使用TCHAR的两个分区来获取缓冲区的实际大小 使用UNICODE。

2)根据您的经验或偏好,这个版本的printf仍然是最好用的吗? 因为搜索MSDN我发现了printf这么多不同的可变版本。

3)您是否会更改代码中的任何内容以使其更具可移植性或更多&#34;正确&#34; ...我没有看到任何错误处理,并且从我所看到的内容总是更好使用作为黑盒子的va_宏,以便您的代码可以更轻松。

如果有些问题听起来很愚蠢,我很抱歉,但是我从这个例子中感到不知所措。

提前谢谢。

1 个答案:

答案 0 :(得分:1)

1)MessageBox是一个函数。他正在返回方法MessageBox的返回值。请查看此处的文档:https://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=vs.85).aspx

2)这是vsnwprintf https://msdn.microsoft.com/en-us/library/1kt27hek.aspx的所有现有变体。每种类型采用不同的统一大小(例如:byte,char,tchar,wchar等)。

此methot的第二个参数请求缓冲区中的元素数。鉴于sizeof (szBuffer)为您提供bytes中的缓冲区大小(而不是缓冲区内TCHAR的数量),您必须将其除以TCHAR的大小({{1} })。因此,sizeof(TCHAR)

3)我在这一点上有点失落。会介意改进吗?