Click to See Complete Forum and Search --> : a replacement for wsprintf


YourSurrogateGod
June 8th, 2004, 12:17 PM
I just wrote a program and would like a better way of outputting text to the screen. I used to fool around with wsprintf quite often, but that's quite unsafe considering that a buffer overflow can easily occur. I tried to use the StringCbPrintf and wnsprintf functions, but unfortunately, none worked :( . Below are the 2 uses of the functions...

[edit]
StringCbPrintf...

#include <windows.h>
#include <strsafe.h>
.....
// ARRAY_SIZE is a pre-defined that's equal to 100
DrawText(hdc,
StringCbPrintf(szBuffer, ARRAY_SIZE, TEXT(" %d %d %d "),
GetRValue(cr), GetGValue(cr), GetBValue(cr)),
-1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);


[edit]
wnsprintf...

#include <windows.h>
#include <shlwapi.h>
........
DrawText(hdc,
wnsprintf(szBuffer, ARRAY_SIZE, TEXT(" %d %d %d "),
GetRValue(cr), GetGValue(cr), GetBValue(cr)),
-1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

...and I keep getting these errors...

warning C4013: 'wnsprintf' undefined; assuming extern returning int
[edit]
Linking...
whatclr.obj : error LNK2001: unresolved external symbol _wnsprintf
Debug/whatclr.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

Does anyone know the problem? Thanks in advance.

Paul McKenzie
June 8th, 2004, 01:26 PM
Look in MSDN. Here is what it states about wnsprintf

Requirements
<snip>
Import Library: Shlwapi.lib.

Did you include the import library in your project?

Regards,

Paul McKenzie

YourSurrogateGod
June 8th, 2004, 02:38 PM
Yup. I put it into the "Object/library modules:" but it still doesn't work.

For the StringCbPrintf, even if I included the strsafe.lib file in the same place that I described above, it tells me that strsafe.h is unrecognized :confused: .

I hope it's not some update stuff that I have to download.

Paul McKenzie
June 8th, 2004, 04:25 PM
If you are using Visual C++ 6.0, place the library directly in your project workspace instead of specifying it in the project settings. There is a bug in the VC++ IDE where sometimes, libraries specified in the project settings are ignored.

Regards,

Paul McKenzie

YourSurrogateGod
June 9th, 2004, 10:55 AM
Umm... Paul. What happens when I put the file in and it still doesn't work. Here's my entire program...
[edit]

// whatclr.c:

#include <windows.h>
#include <shlwapi.h>

#define ID_TIMER 1
#define ARRAY_SIZE 100

void FindWindowSize(int *, int *);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WhatClr");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
int cxWindow;
int cyWindow;

wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;

if(!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires a Windows OS that supports Unicode."),
szAppName, MB_ICONERROR);

return 0;
}

FindWindowSize(&cxWindow, &cyWindow);

hwnd = CreateWindow(szAppName, TEXT("What Color"),
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER, CW_USEDEFAULT,
CW_USEDEFAULT, cxWindow, cyWindow, NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static COLORREF cr;
static COLORREF crLast;
static HDC hdcScreen;
HDC hdc;
PAINTSTRUCT ps;
POINT pt;
RECT rect;
TCHAR szBuffer[ARRAY_SIZE];

switch(message)
{
case WM_CREATE:
hdcScreen = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
SetTimer(hwnd, ID_TIMER, 100, NULL);

return 0;

case WM_TIMER:
GetCursorPos(&pt);

cr = GetPixel(hdcScreen, pt.x, pt.y);

if(cr != crLast)
{
crLast = cr;
InvalidateRect(hwnd, NULL, FALSE);
}

return 0;

case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);

GetClientRect(hwnd, &rect);

FillRect(hdc, &rect, CreateSolidBrush(cr));

// Old wsprintf function, without any protection against buffer overflows
wnsprintf(szBuffer, ARRAY_SIZE, TEXT(" %d %d %d "), GetRValue(cr),
GetGValue(cr), GetBValue(cr));

DrawText(hdc, szBuffer, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

EndPaint(hwnd, &ps);

return 0;

case WM_DESTROY:
DeleteDC(hdcScreen);
KillTimer(hwnd, ID_TIMER);

PostQuitMessage(0);

return 0;
}

return DefWindowProc(hwnd, message, wParam, lParam);
}


void FindWindowSize(int * pcxWindow, int * pcyWindow)
{
HDC hdcScreen;
TEXTMETRIC tm;

hdcScreen = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
GetTextMetrics(hdcScreen, &tm);
DeleteDC(hdcScreen);

* pcxWindow = 3 * GetSystemMetrics(SM_CXBORDER) + 20 * tm.tmAveCharWidth;
* pcyWindow = 3 * GetSystemMetrics(SM_CYBORDER) +
GetSystemMetrics(SM_CYCAPTION) + 2 * tm.tmHeight;
}

Mick
June 9th, 2004, 11:00 AM
Do you have the Platform SDK installed, and are the directories first in the tools->options->directories for lib/include?

YourSurrogateGod
June 9th, 2004, 11:13 AM
These are the options that I'm looking at the moment...

// when I select the "Include files" tab in the "Show directories for:"
C:\Program Files\Microsoft Visual Studio\VC98\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\MFC\INCLUDE
C:\Program Files\Microsoft Visual Studio\VC98\ATL\INCLUDE

// when I select the "Library files" tab
C:\Program Files\Microsoft Visual Studio\VC98\LIB
C:\Program Files\Microsoft Visual Studio\VC98\MFC\LIB

// And just for the record, I never fudged with these options :)


Why is it that I'm getting the feeling that this will be something stupid again :) .

Mick
June 9th, 2004, 11:18 AM
Have you downloaded the Platform SDK? :p If you have then you need to make those directories first in your options settings.

Like:
<sdk install dir>\include
<sdk install dir>\lib

Platform SDK full install page download:

http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm


default

http://www.microsoft.com/msdownload/platformsdk/sdkupdate/default.htm

Mick
June 9th, 2004, 11:19 AM
The SDK contains the latest updates to the windows API and various other interfaces, the function you are looking for is in the updated shlwapi.lib

BUT of course you can just declare the prototype and use LoadLibrary(...)/GetProcAddress(...) if you wanted to. But since your exploring/learning I would suggest getting the SDK ASAP.

YourSurrogateGod
June 9th, 2004, 11:23 AM
Forgot to add this earlier. This is how my program would look like in an ideal situation.

// whatclr.c:

#include <windows.h>
#include <strsafe.h>

#define ID_TIMER 1
#define ARRAY_SIZE 100

void FindWindowSize(int *, int *);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("WhatClr");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
int cxWindow;
int cyWindow;

wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;

if(!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires a Windows OS that supports Unicode."),
szAppName, MB_ICONERROR);

return 0;
}

FindWindowSize(&cxWindow, &cyWindow);

hwnd = CreateWindow(szAppName, TEXT("What Color"),
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_BORDER,
CW_USEDEFAULT, CW_USEDEFAULT, cxWindow, cyWindow, NULL, NULL, hInstance, NULL);

ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);

while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static COLORREF cr;
static COLORREF crLast;
static HDC hdcScreen;
HDC hdc;
PAINTSTRUCT ps;
POINT pt;
RECT rect;
TCHAR szBuffer[ARRAY_SIZE];

switch(message)
{
case WM_CREATE:
hdcScreen = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
SetTimer(hwnd, ID_TIMER, 100, NULL);

return 0;

case WM_TIMER:
GetCursorPos(&pt);

cr = GetPixel(hdcScreen, pt.x, pt.y);

if(cr != crLast)
{
crLast = cr;
InvalidateRect(hwnd, NULL, FALSE);
}

return 0;

case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);

GetClientRect(hwnd, &rect);

FillRect(hdc, &rect, CreateSolidBrush(cr));

StringCbPrintf(szBuffer, ARRAY_SIZE, TEXT(" %d %d %d "), GetRValue(cr),
GetGValue(cr), GetBValue(cr));

DrawText(hdc, szBuffer, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

EndPaint(hwnd, &ps);

return 0;

case WM_DESTROY:
DeleteDC(hdcScreen);
KillTimer(hwnd, ID_TIMER);

PostQuitMessage(0);

return 0;
}

return DefWindowProc(hwnd, message, wParam, lParam);
}


void FindWindowSize(int * pcxWindow, int * pcyWindow)
{
HDC hdcScreen;
TEXTMETRIC tm;

hdcScreen = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
GetTextMetrics(hdcScreen, &tm);
DeleteDC(hdcScreen);

* pcxWindow = 3 * GetSystemMetrics(SM_CXBORDER) + 20 * tm.tmAveCharWidth;
* pcyWindow = 3 * GetSystemMetrics(SM_CYBORDER) +
GetSystemMetrics(SM_CYCAPTION) + 2 * tm.tmHeight;
}

You can just copy and paste the code. If you get it to run with the 'StringCbPrintf' function, please tell me what you did. Thank you.

YourSurrogateGod
June 9th, 2004, 11:28 AM
Darn, almost 350 MBs? Too bad my computer at home has only a 10 GB hard drive :( . If I want to pull this off at work I need administrative rights and the guy who can do that already went home.

Thanks for the tip Mick :thumb: .

But Mick...
Keep talking about the "LoadLibrary(...)/GetProcAddress(...)", it sounds interesting :) . As far as I'm concerned it's exploration/learning, just not with alcohol ;) .

Mick
June 9th, 2004, 11:30 AM
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/strings/usingstrsafefunctions.asp

Same answer...download the platform SDK...

Bond
June 9th, 2004, 11:35 AM
Works just fine for me. Nice little program (though I would set the timer lower :)).

As others have said, STRSAFE.H is not included in the VC6.0 release. You need to have the Platform SDK installed. I believe the latest version is from Feb, 2003.

I did a search of my hard drive and the only place STRSAFE.H was found was in:
c:\program files\microsoft sdk\include

Mick
June 9th, 2004, 12:07 PM
Originally posted by YourSurrogateGod
But Mick...
Keep talking about the "LoadLibrary(...)/GetProcAddress(...)", it sounds interesting :) . As far as I'm concerned it's exploration/learning, just not with alcohol ;) .

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/loadlibrary.asp

Read the docs, look at the example, questions? ask...

YourSurrogateGod
June 9th, 2004, 12:44 PM
Originally posted by Bond
(though I would set the timer lower :)).

neh... I got that thingy from Petzold's book. Here are some of the modifications that I made to it in order to make respond better...

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static COLORREF cr;
static COLORREF crLast;
static HDC hdcScreen;
HDC hdc;
PAINTSTRUCT ps;
POINT pt;
RECT rc;
TCHAR szBuffer[ARRAY_SIZE];

switch(message)
{
case WM_CREATE:
hdcScreen = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);

return 0;

case WM_LBUTTONDOWN:
SetCapture(hwnd);

return 0;

case WM_LBUTTONUP:
ReleaseCapture();

return 0;

case WM_MOUSEMOVE:
GetCursorPos(&pt);

cr = GetPixel(hdcScreen, pt.x, pt.y);

if(cr != crLast)
{
crLast = cr;
InvalidateRect(hwnd, NULL, FALSE);
}

return 0;

case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);

GetClientRect(hwnd, &rc);

// code for inverted color
//FillRect(hdc, &rc, CreateSolidBrush(RGB(255 - GetRValue(cr), 255 - GetGValue(cr),
// 255 - GetBValue(cr))));
//wsprintf(szBuffer, TEXT(" %02d %02d %02d "),
// 255 - GetRValue(cr), 255 - GetGValue(cr), 255 - GetBValue(cr));


// non-inverted color
FillRect(hdc, &rc, CreateSolidBrush(cr));
wsprintf(szBuffer, TEXT(" %02d %02d %02d "),
GetRValue(cr), GetGValue(cr), GetBValue(cr));

DrawText(hdc, szBuffer, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

EndPaint(hwnd, &ps);

return 0;

case WM_DESTROY:
DeleteDC(hdcScreen);
KillTimer(hwnd, ID_TIMER);
PostQuitMessage(0);

return 0;
}

return DefWindowProc(hwnd, message, wParam, lParam);
}

You can fool around where and how you want to capture the mouse, in case your little finger will get tired over time ;) .

And here's the kicker. You see those bold parts, well comment out the one that says "// code for non-inverted color" and uncommment the part that says "// code for inverted color". I thought that was pretty cool. It'll work just as well for the program with the timer ;) .

And here's a question that I've been dying to ask. How do some of the members get the colors for their 'if' and other statements? It looks pretty cool and makes programs alot easier to read, I wanted to put that in all of my posts so that others will find it easier to read it.

YourSurrogateGod
June 10th, 2004, 09:49 AM
I have a follow up question on the above program....

What does the function GetSystemMetrics() do exactly when I input SM_CXBORDER(it's located in the FindWindowSize(int *, int*); method of my program)?

I looked at msdn it says that SM_CYBORDER and SM_CXBORDER are for "Width and height of a window border, in pixels."

My question is that isn't that the same as using LOWORD(lParam) and HIWORD(lParam)?

If that's the case, why not use that?

Or also use GetSystemMetrics instead of LOWORD and HIWORD?

Thanks in advance.

Bond
June 10th, 2004, 11:15 AM
It means the frame border surrounding your window -- the edges that you grab ahold of to resize your window. They're usually just a few pixels wide/tall.

RussG1
June 11th, 2004, 03:15 AM
Originally posted by YourSurrogateGod
And here's a question that I've been dying to ask. How do some of the members get the colors for their 'if' and other statements? It looks pretty cool and makes programs alot easier to read, I wanted to put that in all of my posts so that others will find it easier to read it.
You can use the PHP tags instead of CODE tags, it does some some syntax highlighting.

You can use COLOR tags directly within the CODE tags.

You can use Yves M's program that does syntax highlighting. If you ever read one of his posts, you may have seen the following at the bottom.
Originally posted by Yves M
Get this small utility (http://www.codeguru.com/Cpp/misc/samples/codehighlighting/article.php/c4693) to do basic syntax highlighting in vBulletin forums (like Codeguru) easily.
Supports C++ and VB out of the box, but can be configured for other languages.