Co to jest LPCTSTR?


37

czym jest LPCTSTRi jak LPCTSTR(na przykład HDC) i co oznacza?



3
Właśnie dlatego kochamy Microsoft.
zxcdw 12.04.13

2
Te „typy” zawsze wykazują niespodzianki, np. Kiedy to robisz LPCSTR p, q;i chcesz const char *p, *q;. Czy możesz odmówić ich użycia?
ott--

9
Obrzydliwość.
Thomas Eding 16.04.13

2
64-bitowe przenoszenie 32-bitowej aplikacji wymaga znajomości takich terminologii
nadmierna wymiana

Odpowiedzi:


76

Cytując Briana Kramera na forach MSDN

LPCTSTR= L ‌ong P ‌ointer do C ‌onst T ‌CHAR STR ‌ing (Nie martw się, długi wskaźnik jest taki sam jak wskaźnik. Były dwa smaki wskaźników pod 16-bitowymi oknami.)

Oto tabela:

  • LPSTR = char*
  • LPCSTR = const char*
  • LPWSTR = wchar_t*
  • LPCWSTR = const wchar_t*
  • LPTSTR= w char* or wchar_t*zależności od_UNICODE
  • LPCTSTR= w const char* or const wchar_t*zależności od_UNICODE

29
Za każdym razem, gdy widzę taką nazwę, mam ochotę się skulić. Jest w tym coś, co sprawia, że ​​czuję się nieswojo. (+1 BTW)
Donal Fellows

2
Kiedy powinienem używać tego rodzaju wskaźnika?
Florian Margaine

@FlorianMargaine Gdy interfejs API mówi. Do tego czasu używaj tylko „właściwych” typów
James

1
ostrzegamy, jest tu wiele ostrzeżeń. wchar_t jest 16-bitowym typem, ale może być używany do przechowywania zarówno znaków Unicode zakodowanych w ucs2, jak i utf-16. utf-16 może używać wielu wchar_t do kodowania pojedynczej litery, ucs2 obsługuje tylko podzbiór zestawu znaków Unicode. To, które funkcje API należy wywołać, zależy również od zastosowanego kodowania.
Michael Shaw,

2
Najgorsze jest DWORD, które kiedyś było 32-bitowym podwójnym słowem, ale obecnie jest 32-bitowe pół słowa :-)
gnasher729

6

Nie trzeba nigdy używać żadnego z typów związanych z TCHAR.

Te typy, wszystkie typy struktur, które ich używają, i wszystkie powiązane funkcje są odwzorowywane w czasie kompilacji na wersję ANSI lub UNICODE (na podstawie konfiguracji projektu). Wersje ANSI zazwyczaj mają literę A dołączoną na końcu nazwy, a wersje Unicode dołączają literę W. Możesz użyć ich jawnie, jeśli wolisz. MSDN zanotuje to, gdy będzie to konieczne, na przykład wyświetla tutaj funkcję MessageBoxIndirectA i MessageBoxIndirectW: http://msdn.microsoft.com/en-us/library/windows/desktop/ms645511(v=vs.85).aspx

O ile nie atakujesz systemu Windows 9x, w którym brakuje implementacji wielu funkcji Unicode, nie ma potrzeby używania wersji ANSI. Jeśli celujesz w system Windows 9x, możesz użyć TCHAR do zbudowania pliku binarnego ansi i Unicode z tej samej bazy kodu, o ile twój kod nie zakłada, czy TCHAR jest char lub char.

Jeśli nie obchodzi Cię Windows 9x, zalecamy skonfigurowanie projektu jako Unicode i traktowanie TCHAR jako identycznego z WCHAR. Możesz jawnie korzystać z funkcji i typów W, jeśli wolisz, ale dopóki nie planujesz uruchomić projektu w systemie Windows 9x, nie ma to większego znaczenia.


0

Te typy są udokumentowane w Typach danych systemu Windows w witrynie MSDN:

LPCTSTR

LPCWSTRJeśli UNICODEjest zdefiniowana, LPCSTRinaczej. Aby uzyskać więcej informacji, zobacz Typy danych systemu Windows dla ciągów.

Ten typ jest zadeklarowany w WinNT.h w następujący sposób:

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

LPCWSTR

Wskaźnik do stałego zakończonego znakiem null ciągu 16-bitowych znaków Unicode. Aby uzyskać więcej informacji, zobacz Zestawy znaków używane przez czcionki.

Ten typ jest zadeklarowany w WinNT.h w następujący sposób:

typedef CONST WCHAR *LPCWSTR;

HDC

Uchwyt kontekstu urządzenia (DC).

Ten typ jest zadeklarowany w WinDef.h w następujący sposób:

typedef HANDLE HDC;

0

Wiem, że to pytanie zostało zadane już jakiś czas temu i nie próbuję bezpośrednio odpowiedzieć na dokładnie oryginalne pytanie, ale ponieważ to konkretne pytanie ma przyzwoitą ocenę, chciałbym tu dodać trochę dla przyszłych czytelników. Ma to bardziej konkretny charakter Win32 API typedefsi sposób ich rozumienia.

Jeśli ktoś kiedykolwiek programował system Windows w czasach 32-bitowych maszyn od Windows 95 aż do Windows 7-8, rozumie i wie, że Win32 APIjest załadowany typedefsi że większość jego funkcji i struktur, które mają zostać wypełnione i używane w dużej mierze na nich polegają.


Oto podstawowy program systemu Windows, który można przedstawić jako demonstrację.

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

To ledwo wystarczający kod do renderowania aplikacji Windows. Jest to najbardziej podstawowa konfiguracja zainicjować gołe minimalne właściwości czynią podstawową okno i jak widać jest już załadowany typedefsz Win32 api.


Rozbijmy to, patrząc na funkcje WinMaini InitWindowsApp: Pierwszą rzeczą są parametry funkcji HINSTANCEi PSTR:

WinMainakceptuje pojedynczy HINSTANCEobiekt, podczas gdy InitWindowsAppakceptuje dwa HINSTANCEobiekty obiekt PSTR lub inny typedefciąg znaków i int.

Użyję InitWindowsApptutaj funkcji, ponieważ da ona opis obiektu w obu funkcjach.

Pierwszy HINSTANCEjest zdefiniowany jako H ile do INSTANCE, a ten jest najczęściej używany w aplikacji. Drugi jest drugim HANDLEdo poprzedniej INSTANCJI, która jest już rzadko używana. Został on zachowany dla starszych celów, aby nie musiał zmieniać WinMain()podpisu funkcji, który zepsułby wiele już istniejących aplikacji w tym procesie. Trzecim parametrem jest P ointer do STR inż.

Musimy więc zapytać samych siebie, co to jest HANDLE? Jeśli przyjrzymy się Win32 APIznajdującym się tutaj dokumentom: Typy danych systemu Windows , możemy łatwo to sprawdzić i sprawdzić, czy jest zdefiniowane jako:

Uchwyt do obiektu. Ten typ jest zadeklarowany w WinNT.h w następujący sposób:

typedef PVOID HANDLE; 

Teraz mamy inny typedef. Co jest PVOID? To powinno być oczywiste, ale spójrzmy na to w tej samej tabeli ...

Wskaźnik do dowolnego typu. Jest to zadeklarowane w WinNT.h

typedef void *PVOID;

A HANDLEsłuży do deklarowania wielu obiektów w Win32 APItakich rzeczach jak:

  • HKEY - Uchwyt do klucza rejestru. Zadeklarowano w WinDef.h
    • typdef HANDLE HKEY;
  • HKL - Uchwyt do identyfikatora lokalizacji. Zadeklarowano w WinDef.h
    • typdef HANDLE HKL;
  • HMENU - Uchwyt do menu. Zadeklarowano w WinDef.h
    • typdef HANDLE HMENU;
  • HPEN - Uchwyt do długopisu. Zadeklarowano w WinDef.h
    • typedef HANDLE HPEN;
  • HWND - Uchwyt do okna. Zadeklarowano w WinDef.h
    • typedef HANDLE HWND;
  • ... i tak dalej, takie jak HBRUSH, HCURSOR, HBITMAP, HDC, HDESK, itd.

Są to wszystkie typedefsdeklarowane za pomocą a, typedefktóre jest a, HANDLEa HANDLEsamo jest zadeklarowane jako typedefod a, PVOIDktóre jest również a typedefdo a void pointer.


Więc jeśli chodzi o LPCTSTRto, możemy znaleźć to w tych samych dokumentach:

Jest zdefiniowany jako LPCWSTRif UNICODElub w LPCSTRinny sposób.

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

Mam więc nadzieję, że pomoże to w zrozumieniu sposobu użycia, typedefsszczególnie w przypadku typów danych Windows, które można znaleźć w Win32 API.


Wiele typów uchwytów jest silniej typowanych niż tylko HANDLEaliasy po aktywowaniu STRICTmakra. Myślę, że to domyślna opcja w nowych projektach.
Sebastian Redl

@SebastianRedl Może być; ale nie próbowałem wchodzić w zbyt dużą głębię interfejsu API i rygorystycznie mocno wpisanych aspektów tego języka. Był to raczej przegląd interfejsu API Win32 i jego typów danych przy użyciu typedefs ...
Francis Cugler,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.