Win32

Balloon Tooltips
Win32 c win32
Published: 2008-06-12
Balloon Tooltips

In the Windows XP login screen, the password text box will warn you with a balloon tooltip if you accidentally turn Caps Lock on. The balloon tooltip appears to be a Windows tooltip common control with the TTS_BALLOON style.

To replicate this functionality, I decided to write a function called ShowMsgBalloon() which, given a control and the various balloon tooltip parameters, creates and shows the balloon tooltip below the control.

Read more...
STL Objects and Win32 Module Boundaries
C++ c++ stl win32
Published: 2008-01-04
STL Objects and Win32 Module Boundaries

Let’s say you have the following function:

1
2
3
4
void AppendChar(std::string& s, char ch)
{
    s += ch;
}

What happens if this function is exported as an ordinal function from a DLL (not an inlined piece of code inside a header) and you call it from an EXE?

It works most of the time. When it doesn’t, it corrupts your heap and causes a spectacular mess.

Read more...
Custom-Drawn Win32 Tooltips
Win32 c win32
Published: 2007-08-29
Custom-Drawn Win32 Tooltips

Like many common controls, the tooltip control supports custom drawing for maximum flexibility. This is a quick tutorial on how to use the tooltip custom draw facility.

First, start with the following scratch program (which is a slightly modified version of Raymond Chen’s scratch program):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <tchar.h>

#define WND_CLASS_NAME TEXT("Scratch")

HINSTANCE g_hinst;

BOOL OnCreate(HWND hwnd, LPCREATESTRUCT lpcs)
{
    return TRUE;
}

void OnDestroy(HWND hwnd)
{
    PostQuitMessage(0);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT uiMsg, WPARAM wParam,
                         LPARAM lParam)
{
    switch (uiMsg)
    {
    HANDLE_MSG(hwnd, WM_CREATE, OnCreate);
    HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy);
    }

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

BOOL RegisterWindowClass()
{
    WNDCLASS wc;
    ATOM atom;

    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = g_hinst;
    wc.hIcon = NULL;
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = WND_CLASS_NAME;

    atom = RegisterClass(&wc);
    return (atom != 0);
}

int WINAPI _tWinMain(HINSTANCE hinst, HINSTANCE hinstPrev,
                     LPTSTR lpCmdLine, int nCmdShow)
{
    INITCOMMONCONTROLSEX icc;
    int ret = EXIT_FAILURE;

    g_hinst = hinst;

    // We will need the tooltip common control
    icc.dwSize = sizeof(icc);
    icc.dwICC = ICC_WIN95_CLASSES;
    if (InitCommonControlsEx(&icc))
    {
        if (RegisterWindowClass())
        {
            HWND hwnd = CreateWindow
                (
                WND_CLASS_NAME,
                TEXT("Scratch"),
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT, CW_USEDEFAULT,
                CW_USEDEFAULT, CW_USEDEFAULT,
                NULL,
                NULL,
                hinst,
                );
            if (hwnd != NULL)
            {
                MSG msg;

                (void) ShowWindow(hwnd, nCmdShow);
                while (GetMessage(&msg, NULL, 0, 0)) {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }

                ret = EXIT_SUCCESS;
            }
        }
    }

    return ret;
}

Next, we’ll add a tooltip to this window. We’re not going to do anything fancy like tooltip multiplexing so we’ll use TTF_SUBCLASS.

Read more...
Win32: Getting LOGFONT from HFONT
Win32 win32
Published: 2007-08-22
Win32: Getting LOGFONT from HFONT

To convert a HFONT to a LOGFONT, use the GDI function GetObject(), as in:

1
2
3
LOGFONT lf;
int ret = GetObject(hfont, sizeof(lf), &lf);
// Be sure to check the return value of GetObject

The code is trivial but the function took me forever to find.

Generating and Parsing Localized Numbers In Windows
I18N / L10N win32 localization
Published: 2007-07-11

While Windows supports dozens or even hundreds of languages, its localization APIs require quite a bit of getting used to. Below is how I solved some common problems related to formatting and parsing a number for a specific locale.

Formatting a Number for a Locale

The function GetNumberFormat() formats a number for a particular locale. Its simplest usage looks something like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#define ARRAYSIZE(x) ( sizeof(x) / sizeof(x[0]) )

TCHAR buf[80];
int ret = GetNumberFormat
    (
    LOCALE_USER_DEFAULT, // locale
    0,                   // dwFlags
    TEXT("1234567.89"),  // lpValue
    NULL,                // lpFormat
    buf,                 // lpNumberStr
    ARRAYSIZE(buf)       // cchNumber
    );
ASSERT(ret != 0);

buf now contains the number 1234567.89 formatted for the user’s default locale. For example, for the English-United States locale, buf will contain “1,234,567.89”; for German-Germany, “1.234.567,89”; for Hindi, “12,34,567.89”.

Read more...
Vista Does Not Virtualize Creation Of Shell Links
Win32 vista win32
Published: 2007-05-24
Vista Does Not Virtualize Creation Of Shell Links

Windows Vista developers beware: Vista does not perform file virtualization on the creation of shell links. Consider the following code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// Creates a shell link (a.k.a. shortcut) located at swzLinkFile that points to
// szTargetFile with a description of szDescription.
BOOL CreateLink(LPCTSTR szTargetFile, LPCTSTR szDescription, LPCOLESTR swzLinkFile)
{
    BOOL bRet = FALSE;

    IShellLink* psl;
    HRESULT hr = ::CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
                                    IID_IShellLink, (void**) &psl);
    if (SUCCEEDED(hr))
    {
        IPersistFile* ppf;
        hr = psl->QueryInterface(IID_IPersistFile, (void**) &ppf);
        if (SUCCEEDED(hr))
        {
            hr = psl->SetPath(szTargetFile);
            if (SUCCEEDED(hr))
            {
                hr = psl->SetDescription(szDescription);
                if (SUCCEEDED(hr))
                {
                    hr = ppf->Save(swzLinkFile, TRUE);
                    if (SUCCEEDED(hr))
                    {
                        bSuccess = TRUE;
                    }
                }
            }
            ppf->Release();
        }
        psl->Release();
    }
    return bSuccess;
}

// NOTE: Hardcoding C:\WINDOWS and C:\Program Files is a bad practice. Use
// something like ::SHGetFolderPath().
BOOL bSuccess = CreateLink
    (
    _T("C:\\WINDOWS\\SYSTEM32\\SOL.EXE"),
    _T("Shortcut to SOL.EXE"),
    L"C:\\Program Files\\sol.lnk")
    );

One might expect that the creation of the file C:\Program Files\sol.lnk would be silently redirected by Vista using file virtualization and CreateLink() would succeed, but it doesn’t — the call to IPersistFile::Save() returns E_ACCESSDENIED.

Read more...
Debugging Crashes in Windows Applications: The Null Pointer Dereference
Win32 c debugging win32
Published: 2007-04-25
Debugging Crashes in Windows Applications: The Null Pointer Dereference

Windows C++ developers remain all too familiar with the standard Windows crash dialog. This post is an attempt to teach developers how to understand the data the crash dialog reports to diagnose difficult issues. A basic understanding of assembly language is assumed; for more background on these topics please read Matt Pietrek’s “Under The Hood” articles in the Microsoft Systems Journal February 1998 and June 1998 issues.

To begin with, let’s write an application that crashes with a null pointer dereference:

Read more...
Win32 Shell Lightweight Utility API (shlwapi.dll)
Win32 win32
Published: 2007-02-01
Win32 Shell Lightweight Utility API (shlwapi.dll)

The Win32 shell lightweight utility API (shlwapi.dll) is a cornucopia of useful functions. It appears to be Microsoft’s “dumping ground” for functions without a better home. (I believe Microsoft internal DLL ownership also played a part.) Had I known about shlwapi years ago, it would have saved me considerable programming effort.

Particularly useful are SHCreateStreamOnFile, the path family of functions (e.g. PathCombine), and the registry family of functions (e.g. SHRegGetPath).

However, it appears that Microsoft is slowly moving functionality out of shlwapi into other places. For example, many of shlwapi’s string handling functions have better-designed replacements in Microsoft’s safe string library strsafe. Similarly, shlwapi’s SHRegGetValue has been deprecated in favor of advapi32.dll’s RegGetValue.

Read more...