CRT WinAPI 和可变参数 printf 函数
CRT WinAPI and variadic printf functions
我目前正在学习 WinAPI GUI(编程 Windows Charles Petzold 的第 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()
中的 return 类型并能够 return 像 MessageBox()
这样的完整 C 对象?一般来说,当我 return 像 MessageBox() 这样的完整功能时,我的 return 类型应该是什么?
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) 你会更改代码中的任何内容以使其更便携或更好 "correct"...我没有看到任何错误处理,从我读到的内容来看,使用 va_
宏是黑盒子,因此您的代码可以更便携。
如果有些问题听起来很愚蠢,我很抱歉,但我对这个例子不知所措。
提前谢谢你。
1) MessageBox
是一个函数。他正在 return 计算方法 MessageBox
的 return 值。在此处查看文档: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 等)。
此方法的第二个参数请求缓冲区中的元素数。鉴于 sizeof (szBuffer)
为您提供 bytes
中的缓冲区大小(而不是缓冲区内 TCHAR
的数量),您必须将其除以 TCHAR 的大小(sizeof(TCHAR)
).于是,sizeof (szBuffer) / sizeof (TCHAR)
.
3) 我对此有点迷茫。介意改进一下吗?
我目前正在学习 WinAPI GUI(编程 Windows Charles Petzold 的第 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()
中的 return 类型并能够 return 像 MessageBox()
这样的完整 C 对象?一般来说,当我 return 像 MessageBox() 这样的完整功能时,我的 return 类型应该是什么?
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) 你会更改代码中的任何内容以使其更便携或更好 "correct"...我没有看到任何错误处理,从我读到的内容来看,使用 va_
宏是黑盒子,因此您的代码可以更便携。
如果有些问题听起来很愚蠢,我很抱歉,但我对这个例子不知所措。
提前谢谢你。
1) MessageBox
是一个函数。他正在 return 计算方法 MessageBox
的 return 值。在此处查看文档: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 等)。
此方法的第二个参数请求缓冲区中的元素数。鉴于 sizeof (szBuffer)
为您提供 bytes
中的缓冲区大小(而不是缓冲区内 TCHAR
的数量),您必须将其除以 TCHAR 的大小(sizeof(TCHAR)
).于是,sizeof (szBuffer) / sizeof (TCHAR)
.
3) 我对此有点迷茫。介意改进一下吗?