O que é o LPCTSTR?

37

o que é LPCTSTRe LPCTSTRcomo (por exemplo HDC) e o que representa?

Paul Rooney
fonte
5
Você já viu isso: msdn.microsoft.com/en-us/library/aa300569%28v=vs.60%29.aspx ?
FrustratedWithFormsDesigner
3
É por isso que adoramos a Microsoft.
Zxcdw 12/04
2
Esses "tipos" sempre exibem surpresas, por exemplo, quando você faz LPCSTR p, q;e queria ter const char *p, *q;. Você pode se recusar a usá-los?
ott--
9
Uma abominação.
Thomas Eding
2
64 bits de portabilidade de uma aplicação de 32 bits exige conhecimento de tais terminologias
overexchange

Respostas:

76

Citando Brian Kramer nos fóruns do MSDN

LPCTSTR= L ong P ointer a um C onst T CHAR STR ing (não se preocupa, um ponteiro longo é o mesmo que um ponteiro. Houve dois sabores de ponteiros sob janelas de 16 bits).

Aqui está a tabela:

  • LPSTR = char*
  • LPCSTR = const char*
  • LPWSTR = wchar_t*
  • LPCWSTR = const wchar_t*
  • LPTSTR= char* or wchar_t*dependendo de_UNICODE
  • LPCTSTR= const char* or const wchar_t*dependendo de_UNICODE
fellahst
fonte
29
Toda vez que vejo esse nome, sinto vontade de me encolher. Há algo sobre isso que me deixa desconfortável. (+1 BTW)
Donal Fellows
2
Quando devo usar esse tipo de ponteiro?
Florian Margaine
@FlorianMargaine Quando uma API diz para você. Basta usar os tipos 'apropriados' até então #
James
1
esteja avisado, há muitas advertências aqui. O wchar_t é do tipo 16 bits, mas pode ser usado para armazenar caracteres unicode codificados em ucs2 e utf-16. O utf-16 pode usar vários wchar_t para codificar uma única letra, o ucs2 suporta apenas um subconjunto do conjunto de caracteres unicode. Quais funções da API você precisa chamar também dependem da codificação usada.
Michael Shaw
2
O pior é DWORD, que costumava ser uma palavra dupla de 32 bits, mas hoje é uma meia palavra de 32 bits :-)
gnasher729
6

Não é necessário usar nenhum dos tipos relacionados ao TCHAR.

Esses tipos, todos os tipos de estrutura que os utilizam e todas as funções relacionadas são mapeadas em tempo de compilação para uma versão ANSI ou UNICODE (com base na configuração do seu projeto). As versões ANSI normalmente têm um A anexado ao final do nome e as versões unicode anexam um W. Você pode usá-las explicitamente, se preferir. O MSDN observará isso quando necessário, por exemplo, lista uma função MessageBoxIndirectA e MessageBoxIndirectW aqui: http://msdn.microsoft.com/en-us/library/windows/desktop/ms645511(v=vs.85).aspx

A menos que você esteja direcionando o Windows 9x, que carecia de implementações de muitas funções unicode, não há necessidade de usar as versões ANSI. Se você estiver direcionando o Windows 9x, poderá usar o TCHAR para criar um binário ansi e unicode a partir da mesma base de código, desde que o seu código não faça suposições sobre se o TCHAR é um caractere ou um wchar.

Se você não se importa com o Windows 9x, recomendo configurar seu projeto como unicode e tratar o TCHAR como idêntico ao WCHAR. Você pode usar explicitamente as funções e os tipos W, se preferir, mas desde que não planeje executar seu projeto no Windows 9x, isso realmente não importa.

Vincent Povirk
fonte
0

Esses tipos estão documentados em Tipos de dados do Windows no MSDN:

LPCTSTR

Um LPCWSTRif UNICODEé definido, um LPCSTRcaso contrário. Para obter mais informações, consulte Tipos de dados do Windows para seqüências de caracteres

Este tipo é declarado no WinNT.h da seguinte maneira:

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

LPCWSTR

Um ponteiro para uma cadeia constante terminada por nulo constante de caracteres Unicode de 16 bits. Para mais informações, consulte Conjuntos de caracteres usados ​​por fontes.

Este tipo é declarado no WinNT.h da seguinte maneira:

typedef CONST WCHAR *LPCWSTR;

HDC

Um identificador para um contexto de dispositivo (DC).

Este tipo é declarado no WinDef.h da seguinte maneira:

typedef HANDLE HDC;
CodesInChaos
fonte
0

Sei que essa pergunta foi feita há algum tempo e não estou tentando responder diretamente à pergunta original exata, mas como essa pergunta / pergunta específica tem uma classificação decente, gostaria de adicionar um pouco aqui para futuros leitores. Isso tem a ver mais especificamente com o Win32 API typedefse como entendê-los.

Se alguém já fez alguma programação do Windows durante a era das máquinas de 32 bits, do Windows 95 até o Windows 7-8, ele entende e sabe que ele Win32 APIestá carregado typedefse que a maioria de suas funções e estruturas devem ser preenchidas e usado dependem fortemente deles.


Aqui está um programa básico do Windows para dar como demonstração.

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

Este é apenas um código suficiente para renderizar um aplicativo do Windows. Essa é a configuração mais básica para inicializar as propriedades mínimas vazias para renderizar uma janela básica e, como você pode ver, ela já está carregada typedefsno Win32 api.


Vamos analisar detalhadamente as funções WinMaine InitWindowsApp: a primeira coisa são os parâmetros das funções HINSTANCEe PSTR:

WinMainaceita um único HINSTANCEobjeto enquanto InitWindowsAppaceita dois HINSTANCEobjetos, um objeto PSTR ou alguma outra typedefstring e um int.

Usarei a InitWindowsAppfunção aqui, pois ela fornecerá uma descrição do objeto nas duas funções.

O primeiro HINSTANCEé definido como um H andle para um INSTANCE e esse é o mais usado para o aplicativo. O segundo é outro HANDLEde uma Instância Anterior que raramente é mais usada. Foi mantido para fins legados para não precisar alterar a WinMain()assinatura da função que quebraria muitos aplicativos já existentes no processo. O terceiro parâmetro é um P ointer para uma STR ing.

Então temos que perguntar a nós mesmos o que é um HANDLE? Se procurarmos nos Win32 APIdocumentos encontrados aqui: Tipos de dados do Windows , podemos consultá-lo facilmente e ver se ele está definido como:

Um identificador para um objeto. Este tipo é declarado no WinNT.h da seguinte maneira:

typedef PVOID HANDLE; 

Agora temos outro typedef. O que é um PVOID? Bem, deve ser óbvio, mas vamos procurar isso na mesma tabela ...

Um ponteiro para qualquer tipo. Isso é declarado no WinNT.h

typedef void *PVOID;

A HANDLEé usado para declarar muitos objetos Win32 API, como:

  • HKEY - Um identificador para uma chave do registro. Declarado em WinDef.h
    • typdef HANDLE HKEY;
  • HKL - Um identificador para um identificador de localidade. Declarado em WinDef.h
    • typdef HANDLE HKL;
  • HMENU - Uma alça para um menu. Declarado em WinDef.h
    • typdef HANDLE HMENU;
  • HPEN - Uma alça para uma caneta. Declarado em WinDef.h
    • typedef HANDLE HPEN;
  • HWND - Uma alça para uma janela. Declarado em WinDef.h
    • typedef HANDLE HWND;
  • ... e assim por diante, como HBRUSH, HCURSOR, HBITMAP, HDC, HDESK, etc.

Estes são todos os typedefsque são declarados usando a typedefque é a HANDLEe o HANDLEpróprio é declarado como a typedefde a PVOIDque também é a typedefpara a void pointer.


Então, quando se trata de LPCTSTR, podemos encontrar isso nos mesmos documentos:

É definido como um LPCWSTRse UNICODEestá definido ou de LPCSTRoutra forma.

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

Espero que isso ajude como um guia sobre como entender os usos de typedefsespecialmente com os tipos de dados do Windows que podem ser encontrados no Win32 API.

Francis Cugler
fonte
Muitos dos tipos de identificador são mais fortemente digitados do que apenas serem HANDLEaliases se você ativar a STRICTmacro. Qual é o padrão em novos projetos, eu acho.
Sebastian Redl
@SebastianRedl Poderia ser; mas não estava tentando me aprofundar muito na API e no rigor dos aspectos fortemente tipados da linguagem. Era mais uma visão geral da API do Win32 e de seus tipos de dados pelo uso de typedefs ...
Francis Cugler