Che cos'è LPCTSTR?


37

cos'è LPCTSTRe- LPCTSTRlike (ad esempio HDC) e cosa rappresenta?



3
Questo è il motivo per cui adoriamo Microsoft.
zxcdw,

2
Quei "tipi" mostrano sempre sorprese, ad esempio quando lo fai LPCSTR p, q;e volevi avere const char *p, *q;. Puoi rifiutarti di usarli?
ott--

9
Un abominio.
Thomas Eding,

2
Il porting a 64 bit di un'applicazione a 32 bit richiede la conoscenza di tali terminologie
scambio eccessivo il

Risposte:


76

Citando Brian Kramer sui forum MSDN

LPCTSTR= L ‌ong P ‌intervallo a una C ‌sulla T ‌CHAR STR ‌ing (Non preoccuparti, un puntatore lungo è uguale a un puntatore. C'erano due tipi di puntatori sotto finestre a 16 bit.)

Ecco la tabella:

  • LPSTR = char*
  • LPCSTR = const char*
  • LPWSTR = wchar_t*
  • LPCWSTR = const wchar_t*
  • LPTSTR= a char* or wchar_t*seconda di_UNICODE
  • LPCTSTR= a const char* or const wchar_t*seconda di_UNICODE

29
Ogni volta che vedo quel nome di tipo mi viene voglia di fare il cring. C'è solo qualcosa al riguardo che mi mette a disagio. (+1 BTW)
Donal Fellows

2
Quando dovrei usare questo tipo di puntatore allora?
Florian Margaine,

@FlorianMargaine Quando un'API ti dice di farlo. Basta usare i tipi "corretti" fino ad allora
James

1
attenzione, ci sono molti avvertimenti di cui essere consapevoli qui. wchar_t è un tipo a 16 bit, ma può essere utilizzato per memorizzare caratteri unicode codificati sia ucs2 che utf-16. utf-16 può usare più wchar_t per codificare una singola lettera, ucs2 supporta solo un sottoinsieme del set di caratteri unicode. Le funzioni API che devi chiamare dipendono anche dalla codifica utilizzata.
Michael Shaw,

2
Il peggio è DWORD, che era una doppia parola a 32 bit, ma oggi è una mezza parola a 32 bit :-)
gnasher729

6

Non è necessario mai utilizzare nessuno dei tipi relativi a TCHAR.

Quei tipi, tutti i tipi di struttura che li utilizzano e tutte le funzioni correlate vengono mappati in fase di compilazione su una versione ANSI o UNICODE (in base alla configurazione del progetto). Le versioni ANSI in genere hanno una A aggiunta alla fine del nome e le versioni unicode aggiungono una W. Puoi usarle esplicitamente se preferisci. MSDN lo noterà quando necessario, ad esempio elenca una funzione MessageBoxIndirectA e MessageBoxIndirectW qui: http://msdn.microsoft.com/en-us/library/windows/desktop/ms645511(v=vs.85).aspx

A meno che non si stia prendendo di mira Windows 9x, che mancava di implementazioni di molte funzioni Unicode, non è necessario utilizzare le versioni ANSI. Se hai come target Windows 9x, puoi utilizzare TCHAR per creare un binario ansi e unicode dalla stessa base di codice, purché il tuo codice non faccia ipotesi sul fatto che TCHAR sia un carattere o un wchar.

Se non ti interessa Windows 9x, ti consiglio di configurare il tuo progetto come Unicode e di considerare TCHAR identico a WCHAR. Se lo preferisci, puoi utilizzare esplicitamente le funzioni e i tipi W, ma finché non prevedi di eseguire il tuo progetto su Windows 9x, non importa.


0

Questi tipi sono documentati in Tipi di dati di Windows su MSDN:

LPCTSTR

Un LPCWSTRif UNICODEè definito, un LPCSTRaltrimenti. Per ulteriori informazioni, consultare Tipi di dati di Windows per stringhe.

Questo tipo è dichiarato in WinNT.h come segue:

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

LPCWSTR

Un puntatore a una stringa costante terminata con null di caratteri Unicode a 16 bit. Per ulteriori informazioni, vedere Set di caratteri utilizzati dai caratteri.

Questo tipo è dichiarato in WinNT.h come segue:

typedef CONST WCHAR *LPCWSTR;

HDC

Un handle per un contesto di dispositivo (DC).

Questo tipo è dichiarato in WinDef.h come segue:

typedef HANDLE HDC;

0

So che questa domanda è stata posta qualche tempo fa e non sto cercando di rispondere direttamente alla domanda originale esatta, ma poiché questo particolare Q / A ha una valutazione decente, vorrei aggiungere un po 'qui per i futuri lettori. Questo ha a che fare più specificamente conWin32 API typedefs e come capirli.

Se qualcuno ha mai fatto alcuna programmazione Windows durante l'era delle macchine a 32 bit da Windows 95 a Windows 7-8, capisce e sa che Win32 APIè caricato typedefse che la maggior parte delle sue funzioni e strutture che devono essere riempite e usato fa molto affidamento su di loro.


Ecco un programma Windows di base da dare come dimostrazione.

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

Questo codice è a malapena sufficiente per il rendering di un'applicazione Windows. Questa è la configurazione di base per inizializzare le proprietà minimali nude per il rendering di una finestra di base e, come puoi vedere, è già caricata typedefsda Win32 api.


Analizziamolo guardando le funzioni WinMaine InitWindowsApp: la prima cosa sono i parametri delle funzioni HINSTANCEe PSTR:

WinMainaccetta un singolo HINSTANCEoggetto mentre InitWindowsAppaccetta due HINSTANCEoggetti un oggetto PSTR o qualche altra typedefstringa e un int.

Userò la InitWindowsAppfunzione qui poiché fornirà una descrizione dell'oggetto in entrambe le funzioni.

Il primo HINSTANCEè definito come H andle di un ISTANZA e questo è quello più comunemente usato per l'applicazione. Il secondo è un altro HANDLEdi un ISTANZA precedente che viene raramente utilizzato più. È stato mantenuto per scopi legacy al fine di non dover cambiare la WinMain()firma della funzione che avrebbe rotto molte applicazioni già esistenti nel processo. Il terzo parametro è un P ointer ad uno STR ing.

Quindi dobbiamo chiederci che cos'è un HANDLE? Se guardiamo nei Win32 APIdocumenti trovati qui: Tipi di dati di Windows , possiamo facilmente cercarlo e vedere che è definito come:

Una maniglia per un oggetto. Questo tipo è dichiarato in WinNT.h come segue:

typedef PVOID HANDLE; 

Ora ne abbiamo un altro typedef. Che cos'è un PVOID? Beh, dovrebbe essere ovvio, ma cerchiamo di cercarlo nella stessa tabella ...

Un puntatore a qualsiasi tipo. Questo è dichiarato in WinNT.h

typedef void *PVOID;

A HANDLEè usato per dichiarare molti oggetti in Win32 APIcose come:

  • HKEY - Un handle per una chiave di registro. Dichiarato in WinDef.h
    • typdef HANDLE HKEY;
  • HKL - Un handle per un identificatore locale. Dichiarato in WinDef.h
    • typdef HANDLE HKL;
  • HMENU - Una maniglia per un menu. Dichiarato in WinDef.h
    • typdef HANDLE HMENU;
  • HPEN - Una maniglia per una penna. Dichiarato in WinDef.h
    • typedef HANDLE HPEN;
  • HWND - Una maniglia per una finestra. Dichiarato in WinDef.h
    • typedef HANDLE HWND;
  • ... e così via, come HBRUSH, HCURSOR, HBITMAP, HDC, HDESK, etc.

Questi sono tutto typedefsciò che viene dichiarato usando a typedefche è a HANDLEe lo HANDLEstesso viene dichiarato come typedefda a PVOIDche è anche typedefa a void pointer.


Quindi, quando si tratta di LPCTSTRpossiamo trovarlo negli stessi documenti:

È definito come un LPCWSTRif UNICODEdefinito o LPCSTRaltrimenti.

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

Quindi, si spera, questo aiuterà come guida su come comprendere gli usi typedefssoprattutto con i tipi di dati di Windows che si possono trovare in Win32 API.


Molti tipi di handle sono più fortemente tipizzati rispetto ai semplici HANDLEalias se si attiva la STRICTmacro. Qual è l'impostazione predefinita nei nuovi progetti, credo.
Sebastian Redl

@SebastianRedl Potrebbe essere; ma non stavo cercando di approfondire troppo l'API e la rigidità degli aspetti fortemente tipizzati del linguaggio. Era più una panoramica dell'API Win32 e dei suoi tipi di dati mediante l'uso di typedefs ...
Francis Cugler
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.