Що таке LPCTSTR?


37

що таке LPCTSTRі LPCTSTR-подібне (наприклад HDC) і що воно означає?



3
Ось чому ми просто любимо Microsoft.
zxcdw

2
Ці "типи" завжди викликають сюрпризи, наприклад, коли ви цього LPCSTR p, q;хотіли і хотіли const char *p, *q;. Чи можете ви відмовитися від їх використання?
ott--

9
Огида
Томас Едінг

2
64-бітове перенесення 32-розрядного додатку вимагає знання таких термінологій
переобмін

Відповіді:


76

Цитуючи Брайана Крамера на форумах MSDN

LPCTSTR= L Ong P ointer до C onst T CHAR STR Інг (не хвилюйтеся, довгий покажчик такий же , як покажчик. Були два різновиди покажчиків під 16-бітних Windows.)

Ось таблиця:

  • LPSTR = char*
  • LPCSTR = const char*
  • LPWSTR = wchar_t*
  • LPCWSTR = const wchar_t*
  • LPTSTR= char* or wchar_t*залежно від_UNICODE
  • LPCTSTR= const char* or const wchar_t*залежно від_UNICODE

29
Кожен раз, коли я бачу це ім'я, я відчуваю, як стискається. Про це є просто щось, що робить мені незручно. (+1 BTW)
стипендіати доналу

2
Коли я повинен використовувати такий тип покажчика?
Флоріан Маргайн

@FlorianMargaine Коли API каже вам. Просто використовуйте "належні" типи до цього моменту
Джеймс

1
Попереджуйте, тут є багато застережень. wchar_t - це 16-ти бітний тип, але його можна використовувати для зберігання кодованих символів uncode як ucs2, так і utf-16. utf-16 може використовувати кілька wchar_t для кодування однієї літери, ucs2 підтримує лише підмножину набору символів unicode. Які функції API потрібно викликати, також залежать від використовуваного кодування.
Майкл Шоу

2
Найгірше - DWORD, який раніше був 32-бітним подвійним словом, але сьогодні це 32-бітне половинне слово :-)
gnasher729

6

Ніколи не потрібно використовувати жоден із типів, що стосуються TCHAR.

Ці типи, всі типи структур, які їх використовують, і всі пов'язані з ними функції відображаються під час компіляції у версію ANSI або UNICODE (на основі конфігурації вашого проекту). Версії ANSI зазвичай мають A, доданий до кінця імені, а версії unicode додають W. Ви можете використовувати їх явно, якщо вам зручніше. MSDN відмітить це за необхідності, наприклад, тут перелічено функцію MessageBoxIndirectA та MessageBoxIndirectW: http://msdn.microsoft.com/en-us/library/windows/desktop/ms645511(v=vs.85).aspx

Якщо ви не орієнтуєтесь на Windows 9x, у якій бракувало реалізації багатьох функцій unicode, не потрібно використовувати версії ANSI. Якщо ви орієнтовані на Windows 9x, ви можете використовувати TCHAR для створення бінарних файлів ansi та unicode з тієї самої бази коду, якщо ваш код не передбачає припущень щодо того, чи є TCHAR char чи wchar.

Якщо ви не переймаєтесь Windows 9x, рекомендую налаштувати ваш проект як unicode і розглянути TCHAR як ідентичний WCHAR. Якщо ви хочете, ви можете явно використовувати функції та типи W, але поки ви не плануєте запускати проект у Windows 9x, це насправді не має значення.


0

Ці типи задокументовано у типах даних Windows на MSDN:

LPCTSTR

LPCWSTR, Якщо UNICODEвизначено, в LPCSTRіншому випадку. Для отримання додаткової інформації див. Типи даних Windows для рядків.

Цей тип оголошено в WinNT.h наступним чином:

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

LPCWSTR

Вказівник на постійний рядок з нульовим завершенням 16-бітних символів Unicode. Для отримання додаткової інформації див. Набори символів, використовувані шрифтами.

Цей тип оголошено в WinNT.h наступним чином:

typedef CONST WCHAR *LPCWSTR;

HDC

Ручка до контексту пристрою (DC).

Цей тип оголошено в WinDef.h наступним чином:

typedef HANDLE HDC;

0

Я знаю, що це запитання було задано досить давно, і я не намагаюся безпосередньо відповісти на точне оригінальне запитання, але оскільки цей конкретний Q / A має гідну оцінку, я хотів би трохи додати тут для майбутніх читачів. Це стосується конкретніших питань Win32 API typedefsта способів їх розуміння.

Якщо хтось коли-небудь робив будь-яке програмування Windows під час епохи 32-бітових машин від Windows 95 до Windows 7–8, вони розуміють і знають, що Win32 APIзавантажується typedefsі що більшість їх функцій та структур, які потрібно заповнити і використовувані сильно покладаються на них.


Ось основна програма Windows для демонстрації.

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

Це ледве вистачить коду для візуалізації програми для Windows. Це найголовніша установка для ініціалізації оголених мінімальних властивостей для відображення основного вікна і , як ви можете бачити , що вже завантажено typedefsз Win32 api.


Давайте розбимо його, переглянувши функції WinMainта InitWindowsAppфункції: Перше, що це параметри функцій HINSTANCEта PSTR:

WinMainприймає один HINSTANCEоб'єкт, тоді як InitWindowsAppдва HINSTANCEоб'єкти приймає об'єкт PSTR або інший typedefрядок і int.

Я тут буду використовувати InitWindowsAppфункцію, оскільки вона дасть опис об'єкта в обох функціях.

Перший HINSTANCEвизначається як H andle до ИНСТАНЦИИ , і це той , який найбільш часто використовується для додатка. Друга - це ще HANDLEодна попередня ІНСТАНЦІЯ, яка вже рідко використовується. Він зберігався в минулому для того, щоб не потрібно змінювати WinMain()підпис функції, який би порушив багато вже існуючих додатків у процесі. Третій параметр є Р ointer до STR Инж.

Отже, ми повинні запитати себе, що таке HANDLE? Якщо ми подивимось на Win32 APIдокументи, знайдені тут: Типи даних Windows, ми можемо легко знайти їх і побачити, що він визначається як:

Ручка до предмета. Цей тип оголошено в WinNT.h наступним чином:

typedef PVOID HANDLE; 

Зараз у нас є інша typedef. Що таке PVOID? Ну, це повинно бути очевидно, але давайте подивимось, що це в одній таблиці

Вказівник на будь-який тип. Про це заявлено у WinNT.h

typedef void *PVOID;

A HANDLEвикористовується для оголошення багатьох об'єктів у Win32 APIтаких речах, як:

  • HKEY - Ручка до ключа реєстру. Задекларовано у WinDef.h
    • typdef HANDLE HKEY;
  • HKL - Ручка до ідентифікатора локалі. Задекларовано у WinDef.h
    • typdef HANDLE HKL;
  • HMENU - Ручка до меню. Задекларовано у WinDef.h
    • typdef HANDLE HMENU;
  • HPEN - Ручка до ручки. Задекларовано у WinDef.h
    • typedef HANDLE HPEN;
  • HWND - Ручка до вікна. Задекларовано у WinDef.h
    • typedef HANDLE HWND;
  • ... і так далі , такі як HBRUSH, HCURSOR, HBITMAP, HDC, HDESKі т.д.

Це все, typedefsщо оголошується за допомогою a, typedefщо є a, HANDLEа HANDLEсаме оголошується як a typedefз a, PVOIDщо також є a typedefдо a void pointer.


Отже, коли мова йде про те, LPCTSTRми можемо знайти це в тих же документах:

Він визначається як a, LPCWSTRякщо UNICODEвизначено, або LPCSTRіншим чином.

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

Отож, сподіваємось, це допоможе в якості посібника щодо того, як зрозуміти використання typedefsособливо з типами даних Windows, які можна знайти в Win32 API.


Багато типів ручок набираються сильніше, ніж просто HANDLEпсевдоніми, якщо активувати STRICTмакрос. Я думаю, що за замовчуванням у нових проектах.
Себастьян Редл

@SebastianRedl Це могло бути; але я не намагався вникати в занадто глибину API та суворість сильно набраних аспектів мови. Це був більше огляд API Win32 та його типів даних за допомогою typedefs ...
Френсіс Куглер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.