Qu'est-ce que LPCTSTR?

37

Qu'est-ce qui est LPCTSTRet LPCTSTRressemble (par exemple HDC) et que signifie-t-il?

Paul Rooney
la source
5
Avez-vous vu ceci: msdn.microsoft.com/en-us/library/aa300569%28v=vs.60%29.aspx ?
FrustratedWithFormsDesigner
3
C'est pourquoi nous adorons Microsoft.
Zxcdw
2
Ces "types" présentent toujours des surprises, par exemple lorsque vous le LPCSTR p, q;souhaitez et que vous le souhaitez const char *p, *q;. Pouvez-vous refuser de les utiliser?
ott--
9
Une abomination.
Thomas Eding
2
Le portage 64 bits d'une application 32 bits nécessite la connaissance de telles terminologies
suréchange

Réponses:

76

Citation de Brian Kramer sur les forums MSDN

LPCTSTR= L de P de ointer à un C onst T CHAR STR ING (Ne vous inquiétez pas, un pointeur longue est la même que celle d' un pointeur. Il y avait deux saveurs de pointeurs sous Windows 16 bits.)

Voici la table:

  • LPSTR = char*
  • LPCSTR = const char*
  • LPWSTR = wchar_t*
  • LPCWSTR = const wchar_t*
  • LPTSTR= en char* or wchar_t*fonction de_UNICODE
  • LPCTSTR= en const char* or const wchar_t*fonction de_UNICODE
fellahst
la source
29
À chaque fois que je vois ce nom, j'ai envie de trembler. Il y a juste quelque chose à ce sujet qui me rend mal à l'aise. (+1 BTW)
Donal Fellows
2
Quand devrais-je utiliser ce type de pointeur alors?
Florian Margaine
@ FlorianMargaine Quand une API vous le dit. Il suffit d’utiliser les types appropriés jusqu’alors
James
1
Soyez averti, il y a beaucoup de mises en garde à prendre en compte ici. wchar_t est un type 16 bits, mais peut être utilisé pour stocker les caractères unicode codés ucs2 et utf-16. utf-16 peut utiliser plusieurs wchar_t pour coder une seule lettre, ucs2 ne prenant en charge qu'un sous-ensemble du jeu de caractères unicode. Les fonctions de l'API à appeler dépendent également de l'encodage utilisé.
Michael Shaw
2
Le pire est DWORD, qui était un mot double 32 bits, mais de nos jours est un demi-mot 32 bits :-)
gnasher729
6

Il n'est pas nécessaire d'utiliser l'un des types liés à TCHAR.

Ces types, tous les types de structure qui les utilisent et toutes les fonctions associées sont mappés au moment de la compilation vers une version ANSI ou UNICODE (en fonction de la configuration de votre projet). Les versions ANSI ont généralement un A ajouté à la fin du nom et les versions unicode ajoutent un W. Vous pouvez les utiliser explicitement si vous préférez. MSDN le notera si nécessaire. Par exemple, il répertorie les fonctions MessageBoxIndirectA et MessageBoxIndirectW ici: http://msdn.microsoft.com/en-us/library/windows/desktop/ms645511(v=vs.85).aspx

Si vous ne ciblez pas Windows 9x, qui manquait d'implémentations de nombreuses fonctions unicode, vous n'avez pas besoin d'utiliser les versions ANSI. Si vous ciblez Windows 9x, vous pouvez utiliser TCHAR pour créer un binaire ansi et unicode à partir de la même base de code, à condition que votre code ne présume pas que TCHAR est un caractère ou une valeur.

Si vous ne vous souciez pas de Windows 9x, je vous recommande de configurer votre projet en tant qu'unicode et de traiter TCHAR comme identique à WCHAR. Vous pouvez utiliser explicitement les fonctions et les types W si vous préférez, mais tant que vous ne prévoyez pas d'exécuter votre projet sous Windows 9x, cela n'a pas vraiment d'importance.

Vincent Povirk
la source
0

Ces types sont documentés dans Types de données Windows sur MSDN:

LPCTSTR

Un LPCWSTRif UNICODEest défini, un LPCSTRsinon. Pour plus d'informations, voir Types de données Windows pour les chaînes.

Ce type est déclaré dans WinNT.h comme suit:

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

LPCWSTR

Un pointeur sur une chaîne de caractères Unicode 16 bits à terminaison null constante. Pour plus d'informations, voir Jeux de caractères utilisés par les polices.

Ce type est déclaré dans WinNT.h comme suit:

typedef CONST WCHAR *LPCWSTR;

HDC

Un descripteur de contexte de périphérique (DC).

Ce type est déclaré dans WinDef.h comme suit:

typedef HANDLE HDC;
CodesInChaos
la source
0

Je sais que cette question a été posée il y a un certain temps et que je n'essaie pas de répondre directement à la question d'origine, mais comme cette question / réponse a une note décente, j'aimerais ajouter un peu ici aux futurs lecteurs. Cela concerne plus spécifiquement le Win32 API typedefset comment les comprendre.

Si quelqu'un a déjà fait une programmation Windows pendant l'ère des machines 32 bits à partir de Windows 95 à Windows et jusqu'à 7-8 qu'ils comprennent et savent que l' Win32 APIest chargé avec typedefset que la majorité de leurs fonctions et structures qui doivent être remplies et utilisé dépend fortement d'eux.


Voici un programme Windows de base à donner en démonstration.

#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;
}

C'est à peine assez de code pour rendre une application Windows. Il s’agit de la configuration la plus élémentaire pour initialiser les propriétés minimales nues afin de rendre une fenêtre de base et, comme vous pouvez le constater, elle est déjà chargée typedefsdepuis le Win32 api.


Décomposons en regardant les fonctions WinMainet InitWindowsApp: La première chose à faire sont les paramètres des fonctions HINSTANCEet PSTR:

WinMainaccepte un seul HINSTANCEobjet tandis que InitWindowsAppaccepte deux HINSTANCEobjets, un objet PSTR ou une autre typedefchaîne et un entier.

Je vais utiliser la InitWindowsAppfonction ici car elle donnera une description de l'objet dans les deux fonctions.

Le premier HINSTANCEest défini comme étant un H andle à un INSTANCE et ceci est celui qui est le plus couramment utilisé pour l'application. Le second est un autre exemple HANDLEd’ Instant INSTANCE, qui est rarement utilisé. Elle a été conservée pour des raisons d'héritage afin de ne pas avoir à changer la WinMain()signature de fonction qui casserait de nombreuses applications existantes dans le processus. Le troisième paramètre est un P ointer à un STR ing.

Nous devons donc nous demander ce qu'est un HANDLE? Si nous regardons dans la Win32 APIdocumentation trouvée ici: Types de données Windows, nous pouvons facilement le rechercher et voir qu'il est défini comme suit:

Une poignée à un objet. Ce type est déclaré dans WinNT.h comme suit:

typedef PVOID HANDLE; 

Maintenant nous en avons un autre typedef. Qu'est - ce qu'un PVOID? Cela devrait être évident, mais regardons cela dans le même tableau ...

Un pointeur sur n'importe quel type. Ceci est déclaré dans WinNT.h

typedef void *PVOID;

A HANDLEest utilisé pour déclarer de nombreux objets dans les Win32 APIchoses telles que:

  • HKEY - un descripteur de clé de registre. Déclaré dans WinDef.h
    • typdef HANDLE HKEY;
  • HKL - Un identifiant pour un identifiant de locale. Déclaré dans WinDef.h
    • typdef HANDLE HKL;
  • HMENU - Une poignée pour un menu. Déclaré dans WinDef.h
    • typdef HANDLE HMENU;
  • HPEN - Une poignée à un stylo. Déclaré dans WinDef.h
    • typedef HANDLE HPEN;
  • HWND - Une poignée à une fenêtre. Déclaré dans WinDef.h
    • typedef HANDLE HWND;
  • ... et ainsi de suite, comme HBRUSH, HCURSOR, HBITMAP, HDC, HDESK, etc.

Ce sont tous ceux typedefsqui sont déclarés en utilisant a typedefqui est a HANDLEet le HANDLElui-même est déclaré en tant que typedefde a PVOIDqui est aussi a typedefà a void pointer.


Donc, quand on en vient à LPCTSTRtrouver ça dans les mêmes documents:

Il est défini comme un LPCWSTRif UNICODEest défini ou un LPCSTRautre.

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

J'espère donc que cela vous aidera à comprendre comment utiliser typedefsles types de données Windows, en particulier, disponibles dans le Win32 API.

Francis Cugler
la source
De nombreux types de descripteurs sont plus fortement typés que le simple fait d'être des HANDLEalias si vous activez la STRICTmacro. Quel est le défaut dans les nouveaux projets, je pense.
Sebastian Redl
@SebastianRedl Cela pourrait être; mais je n'essayais pas d'entrer trop dans les détails de l'API ni dans la sévérité des aspects fortement typés du langage. Il s’agissait plutôt d’une vue d’ensemble de l’API Win32 et de ses types de données grâce à l’utilisation de typedefs ...
Francis Cugler