CRT WinAPI and variadic printf functions

450 views Asked by At

I am currently studying WinAPI GUI (Programming Windows 5th edition by Charles Petzold) and C(not C++) .I am trying and want to keep it as pure C as possible and maybe then jump to C++ or C#. My problem relies on using the variadic ***printf***() editions.

Project : I want to make a function that will be able to identify if I am using ASCII, UNICODE or another type of multibyte character set(MBCS) and then format the input accordingly and type the output in a MessageBox().

In the book that I am reading the author is using the source code below to make something similar : 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 ;
}

The program displays the width and height of the video display in pixels by using information obtained from the GetSystemMetrics function. GetSystemMetrics is a useful function for obtaining information about the sizes of various objects in Windows.

From my understanding he is using TCHAR so that his function can handle UNICODE or ASCII. TCHAR is defined as:

#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

while MessageBox() is using the following trick to be able to handle either ASCII either UNICODE:

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

Before trying to code my project(i started but i had questions i couldn nott answer on my own) i would like to solve some puzzles i have not figured out yet.

1)How can he use int as a return type in MessageBoxPrintf() and be able to return a full C-object like MessageBox()?And in general what should my return type be when i return full functions like MessageBox()?

2)The function the author is using is _vsntprintf.MSDN denies it exists but i found this in the source code:

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

Also he is using two divisions with TCHAR to get the actual sizes of the buffer when we are using UNICODE.

2)From your experience or preference is this version of printf still the best to use? Because searching MSDN I found so many different variadic versions of printf.

3)Would you change anything in the code to make it more portable or more "correct"...I don't see any error handling and from what i have read it is always better to use va_ macros which are black boxes so your code can be more portable.

I am sorry if some questions sound stupid but I am overwhelmed from this example.

Thank you in advance.

1

There are 1 answers

1
Danilo Gasques On BEST ANSWER

1) MessageBox is a function. He is returning the return value of the method MessageBox. Take a look at the documentation here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=vs.85).aspx

2) Here's all the existing variations of vsnwprintf https://msdn.microsoft.com/en-us/library/1kt27hek.aspx. Each type takes a different unity size (e.g.: byte, char, tchar, wchar, etc...).

The second argument of this methot requests the number of elements in the buffer. Given that sizeof (szBuffer) gives you the buffer size in bytes ( and not the quantity of TCHARs inside the buffer), you have to divide it by the size of TCHAR (sizeof(TCHAR)). Thus,sizeof (szBuffer) / sizeof (TCHAR).

3) I am a little bit lost on this one. Would mind improving on it?