38

what is LPCTSTR and LPCTSTR-like (for instance HDC) and what it does stand for?

77

Quoting Brian Kramer on the MSDN forums

LPCTSTR = L‌ong P‌ointer to a C‌onst T‌CHAR STR‌ing (Don't worry, a long pointer is the same as a pointer. There were two flavors of pointers under 16-bit windows.)

Here's the table:

  • LPSTR = char*
  • LPCSTR = const char*
  • LPWSTR = wchar_t*
  • LPCWSTR = const wchar_t*
  • LPTSTR = char* or wchar_t* depending on _UNICODE
  • LPCTSTR = const char* or const wchar_t* depending on _UNICODE
  • 29
    Every time I see that type name I feel like cringing. There's just something about it that makes me uncomfortable. (+1 BTW) – Donal Fellows Apr 13 '13 at 8:44
  • 2
    When should I use this kind of pointer then? – Florian Margaine Apr 13 '13 at 9:16
  • @FlorianMargaine When an API tells you to. Just use the 'proper' types until then – James Apr 13 '13 at 13:43
  • 1
    be warned, there are lots of caveats to be aware of here. wchar_t is a 16 bit type, but can be used to store both ucs2 and utf-16 encoded unicode characters. utf-16 may use multiple wchar_t's to encode a single letter, ucs2 only supports a subset of the unicode characterset. Which API functions you need to call also depend on the encoding used. – Michael Shaw Dec 3 '15 at 13:34
  • 2
    The worst is DWORD, which used to be a 32 bit double word, but nowadays is a 32 bit half word :-) – gnasher729 Mar 5 at 8:52
6

There's no need to ever use any of the types relating to TCHAR.

Those types, all structure types that use them, and all related functions are mapped at compile time to an ANSI or UNICODE version (based on your project's configuration). ANSI versions typically have an A appended to the end of the name, and unicode versions append a W. You can use these explicitly if you prefer. MSDN will note this when necessary, for example it lists a MessageBoxIndirectA and MessageBoxIndirectW function here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms645511(v=vs.85).aspx

Unless you are targeting Windows 9x, which lacked implementations of many unicode functions, there's no need to use the ANSI versions. If you are targeting Windows 9x, you can use TCHAR to build an ansi and unicode binary from the same codebase, as long as your code makes no assumptions about whether TCHAR is a char or wchar.

If you don't care about Windows 9x, I recommend configuring your project as unicode and treating TCHAR as identical to WCHAR. You can explicitly use the W functions and types if you prefer, but as long as you don't plan to run your project on Windows 9x, it doesn't really matter.

0

These types are documented at Windows Data Types on MSDN:

LPCTSTR

An LPCWSTR if UNICODE is defined, an LPCSTR otherwise. For more information, see Windows Data Types for Strings.

This type is declared in WinNT.h as follows:

#ifdef UNICODE
 typedef LPCWSTR LPCTSTR; 
#else
 typedef LPCSTR LPCTSTR;
#endif

LPCWSTR

A pointer to a constant null-terminated string of 16-bit Unicode characters. For more information, see Character Sets Used By Fonts.

This type is declared in WinNT.h as follows:

typedef CONST WCHAR *LPCWSTR;

HDC

A handle to a device context (DC).

This type is declared in WinDef.h as follows:

typedef HANDLE HDC;
0

I know that this question was asked quite some time ago and I'm not trying to directly answer the exact original question, but as this particular Q/A has a decent rating I'd like to add a bit here for future readers. This has to do more specifically with the Win32 API typedefs and how to understand them.

If anyone has ever done any Windows programming during the era of the 32bit machines from Windows 95 through and up to Windows 7-8 they understand and know that the Win32 API is loaded with typedefs and that a majority of their functions and structures that are to be filled and used rely heavily on them.


Here is a basic windows program to give as a demonstration.

#include <Windows.h>

HWND ghMainWnd = 0;

bool InitWindowsApp( HINSTANCE, int show );
LRESULT CALLBACK WindowProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
int run();

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pCmdLine, int show ) {
    if ( !InitWindowsApp( hInstance, showCmd ) ) {
        return 0;
    }
    return run();
}

LRESULT CALLBACK WindowProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) {
    switch( msg ) {
        case WM_KEYDOWN: {
            if ( wParam == VK_ESCAPE ) {
                DestroyWindow( ghMainWnd );
            }
            return 0;
         }
         case WM_DESTROY: {
             PostQuitMessage(0);
             return 0;
         }
         default: {
             return DefWindowProc( hWnd, msg, wParam, lParam );
         }
    }
}

bool InitWindowsApp( HINSTANCE hInstance, int nCmdShow ) {

    WNDCLASSEX wc;

    wc.style            = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc      = WindowProc;
    wc.cbClsExtra       = NULL;
    wc.cbWndExtra       = NULL;
    wc.hInstance        = hInstance;
    wc.hIcon            = LoadIcon( NULL, IDI_APPLICATION );
    wc.hIconSm          = LoadIcon( NULL, IDI_APPLICATION );
    wc.hCursor          = LoadCursor( NULL, IDC_ARROW );
    wc.lpszMenuName     = NULL;
    wc.hbrBackground    = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszClassName    = L"Basic Window";
    wc.cbSize           = sizeof( WNDCLASSEX);

    if ( !RegisterClassEx( &wc ) ) {
        MessageBox( NULL, L"Register Class FAILED", NULL, NULL );
        return false;
    }

    ghMainWnd = CreateWindow( 
        L"Basic Window",
        L"Win32Basic",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        NULL, NULL,
        hInstance,
        NULL );
    if ( ghMainWnd == 0 ) {
        MessageBox( NULL, L"Window failed to create", L"Error", MB_OK );
        return false;
    }

    ShowWindow( ghMainWnd, nCmdShow );
    UpdateWindow( ghMainWnd );

    return true;    
}

int run() {
    MSG msg = {0};
    BOOL bReturn = 1;

    while( (bReturn = GetMessage( &msg, NULL, NULL, NULL)) != 0 ) {
        if ( bReturn == -1 ) {
            MessageBox( NULL, L"GetMessage FAILED", L"Error", MB_OK );
            break;
        } else {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }
    return (int)msg.wParam;
}

This is barely enough code to render a windows application. This is the most basic setup to initialize the bare minimal properties to render a basic window and as you can see it is already loaded with typedefs from the Win32 api.


Let's break it down by looking at the WinMain and InitWindowsApp functions: The first thing are the functions' parameters HINSTANCE and PSTR:

WinMain accepts a single HINSTANCE object while InitWindowsApp accepts two HINSTANCE objects a PSTR object or some other typedef string and an int.

I'll use the InitWindowsApp function here since it will give a description of the object in both functions.

The first HINSTANCE is defined as a Handle to an INSTANCE and this is the one that is most commonly used for the application. The second one is another HANDLE to a Previous INSTANCE which is rarely used anymore. It was kept around for legacy purpose in order to not have to change the WinMain() function signature that would break many already existing applications in the process. The third parameter is a Pointer to a STRing.

So we have to ask our selves what is a HANDLE? If we look in the Win32 API docs found here:Windows Data Types we can easily look it up and see that it is defined as:

A handle to an object. This type is declared in WinNT.h as follows:

typedef PVOID HANDLE; 

Now we have another typedef. What is a PVOID? Well it should be obvious but lets look that up in the same table...

A pointer to any type. This is declared in WinNT.h

typedef void *PVOID;

A HANDLE is used to declare many objects in the Win32 API things such as:

  • HKEY - A handle to a registry key. Declared in WinDef.h
    • typdef HANDLE HKEY;
  • HKL - A handle to a locale identifier. Declared in WinDef.h
    • typdef HANDLE HKL;
  • HMENU - A handle to a menu. Declared in WinDef.h
    • typdef HANDLE HMENU;
  • HPEN - A handle to a pen. Declared in WinDef.h
    • typedef HANDLE HPEN;
  • HWND - A handle to a window. Declared in WinDef.h
    • typedef HANDLE HWND;
  • ... and so on such as HBRUSH, HCURSOR, HBITMAP, HDC, HDESK, etc.

These are all typedefs that are declared using a typedef which is a HANDLE and the HANDLE itself is declared as a typedef from a PVOID which is also a typedef to a void pointer.


So when it comes to LPCTSTR we can find that in the same docs:

It is defined as a LPCWSTR if UNICODE is defined or a LPCSTR otherwise.

#ifdef UNICODE
  typedef LPCWSTR LPCSTR;
#else
  typedef LPCSTR LPCTSTR;
#endif

So hopefully this will help as a guide as to how to understand the uses of typedefs especially with the Windows Data Types that can be found in the Win32 API.

  • Many of the handle types are more strongly typed than just being HANDLE aliases if you activate the STRICT macro. Which is the default in new projects, I think. – Sebastian Redl Mar 5 at 11:01
  • @SebastianRedl It could be; but I wasn't trying to go into too much depth of the API and the strictness of the strongly typed aspects of the language. It was more of an overview of the Win32 API and its Data Types by the use of typedefs... – Francis Cugler Mar 5 at 12:51

protected by gnat Mar 9 at 21:44

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?