¿Qué es LPCTSTR?

37

¿Qué es LPCTSTRy LPCTSTRcomo (por ejemplo HDC) y qué significa?

Paul Rooney
fuente
55
¿Has visto esto: msdn.microsoft.com/en-us/library/aa300569%28v=vs.60%29.aspx ?
FrustratedWithFormsDesigner
3
Es por eso que amamos a Microsoft.
zxcdw
2
Esos "tipos" siempre exhiben sorpresas, por ejemplo, cuando lo hace LPCSTR p, q;y lo que quería tener const char *p, *q;. ¿Se puede negar a usarlos?
ott--
9
Una abominación
Thomas Eding
2
64 bit portar de una aplicación de 32 bits requiere el conocimiento de tales terminologías
overexchange

Respuestas:

76

Citando a Brian Kramer en los foros de MSDN

LPCTSTR= L ‌ong P ‌ointer a una C ‌onst T ‌CHAR STR ‌ing (No se preocupe, un puntero largo es lo mismo que un puntero. Había dos tipos de punteros debajo de ventanas de 16 bits).

Aquí está la tabla:

  • LPSTR = char*
  • LPCSTR = const char*
  • LPWSTR = wchar_t*
  • LPCWSTR = const wchar_t*
  • LPTSTR= char* or wchar_t*dependiendo de_UNICODE
  • LPCTSTR= const char* or const wchar_t*dependiendo de_UNICODE
fellahst
fuente
29
Cada vez que veo ese nombre de tipo, me dan vergüenza. Hay algo al respecto que me incomoda. (+1 BTW)
Donal Fellows
2
¿Cuándo debo usar este tipo de puntero entonces?
Florian Margaine
@FlorianMargaine Cuando una API te dice que lo hagas. Solo use los tipos 'apropiados' hasta entonces
James
1
Ten en cuenta que hay muchas advertencias a tener en cuenta aquí. wchar_t es un tipo de 16 bits, pero se puede utilizar para almacenar caracteres unicode codificados ucs2 y utf-16. utf-16 puede usar múltiples wchar_t para codificar una sola letra, ucs2 solo admite un subconjunto del conjunto de caracteres unicode. Las funciones de API que necesita llamar también dependen de la codificación utilizada.
Michael Shaw
2
Lo peor es DWORD, que solía ser una palabra doble de 32 bits, pero hoy en día es una media palabra de 32 bits :-)
gnasher729
6

No hay necesidad de usar ninguno de los tipos relacionados con TCHAR.

Esos tipos, todos los tipos de estructura que los usan y todas las funciones relacionadas se asignan en tiempo de compilación a una versión ANSI o UNICODE (según la configuración de su proyecto). Las versiones ANSI generalmente tienen una A añadida al final del nombre, y las versiones Unicode agregan una W. Puede usarlas explícitamente si lo prefiere. MSDN lo notará cuando sea necesario, por ejemplo, enumera una función MessageBoxIndirectA y MessageBoxIndirectW aquí: http://msdn.microsoft.com/en-us/library/windows/desktop/ms645511(v=vs.85).aspx

A menos que esté apuntando a Windows 9x, que carecía de implementaciones de muchas funciones unicode, no hay necesidad de usar las versiones ANSI. Si está apuntando a Windows 9x, puede usar TCHAR para construir un binario ansi y unicode desde la misma base de código, siempre que su código no haga suposiciones sobre si TCHAR es char o wchar.

Si no le importa Windows 9x, le recomiendo configurar su proyecto como unicode y tratar TCHAR como idéntico a WCHAR. Puede usar explícitamente las funciones y tipos W si lo prefiere, pero siempre que no planee ejecutar su proyecto en Windows 9x, realmente no importa.

Vincent Povirk
fuente
0

Estos tipos se documentan en Tipos de datos de Windows en MSDN:

LPCTSTR

Un LPCWSTRif UNICODEestá definido, un lo LPCSTRcontrario. Para obtener más información, consulte Tipos de datos de Windows para cadenas.

Este tipo se declara en WinNT.h de la siguiente manera:

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

LPCWSTR

Un puntero a una cadena constante terminada en nulo de caracteres Unicode de 16 bits. Para obtener más información, consulte Conjuntos de caracteres utilizados por las fuentes.

Este tipo se declara en WinNT.h de la siguiente manera:

typedef CONST WCHAR *LPCWSTR;

HDC

Un identificador para un contexto de dispositivo (DC).

Este tipo se declara en WinDef.h de la siguiente manera:

typedef HANDLE HDC;
CodesInChaos
fuente
0

Sé que esta pregunta se hizo hace bastante tiempo y no estoy tratando de responder directamente a la pregunta original exacta, pero como este Q / A en particular tiene una calificación decente, me gustaría agregar un poco aquí para futuros lectores. Esto tiene que ver más específicamente con Win32 API typedefsy cómo entenderlos.

Si alguien ha realizado alguna programación de Windows durante la era de las máquinas de 32 bits desde Windows 95 hasta Windows 7-8, entienden y saben que Win32 APIestá cargado typedefsy que la mayoría de sus funciones y estructuras se deben llenar y utilizado confiar en gran medida en ellos.


Aquí hay un programa básico de Windows para dar como demostración.

#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 es apenas un código suficiente para representar una aplicación de Windows. Esta es la configuración más básica para inicializar las propiedades mínimas básicas para representar una ventana básica y, como puede ver, ya está cargada typedefsdesde Win32 api.


Analicemos las funciones WinMainy InitWindowsApp: lo primero son los parámetros de las funciones HINSTANCEy PSTR:

WinMainacepta un solo HINSTANCEobjeto mientras InitWindowsAppacepta dos HINSTANCEobjetos, un objeto PSTR o alguna otra typedefcadena y un int.

Usaré la InitWindowsAppfunción aquí ya que dará una descripción del objeto en ambas funciones.

El primero HINSTANCEse define como un H andle para un INSTANCE y este es el que se usa más comúnmente para la aplicación. El segundo es otro HANDLEde un INSTANCE anterior que rara vez se usa más. Se mantuvo con fines heredados para no tener que cambiar la WinMain()firma de la función que rompería muchas aplicaciones ya existentes en el proceso. El tercer parámetro es una P ointer a un STR ing.

Entonces tenemos que preguntarnos a nosotros mismos ¿qué es un HANDLE? Si buscamos en los Win32 APIdocumentos que se encuentran aquí: Tipos de datos de Windows , podemos buscarlo fácilmente y ver que se define como:

Un asa para un objeto. Este tipo se declara en WinNT.h de la siguiente manera:

typedef PVOID HANDLE; 

Ahora tenemos otro typedef. ¿Qué es un PVOID? Bueno, debería ser obvio, pero busquemos eso en la misma tabla ...

Un puntero a cualquier tipo. Esto se declara en WinNT.h

typedef void *PVOID;

A HANDLEse usa para declarar muchos objetos en Win32 APIcosas como:

  • HKEY - Un identificador para una clave de registro. Declarado en WinDef.h
    • typdef HANDLE HKEY;
  • HKL - Un identificador para un identificador de configuración regional. Declarado en WinDef.h
    • typdef HANDLE HKL;
  • HMENU - Un identificador para un menú. Declarado en WinDef.h
    • typdef HANDLE HMENU;
  • HPEN - Un mango para un bolígrafo. Declarado en WinDef.h
    • typedef HANDLE HPEN;
  • HWND - Un tirador a una ventana. Declarado en WinDef.h
    • typedef HANDLE HWND;
  • ... y así sucesivamente, como HBRUSH, HCURSOR, HBITMAP, HDC, HDESK, etc.

Estos son todos los typedefsque se declaran usando a typedefque es a HANDLEy el HANDLEmismo se declara como a typedefdesde a PVOIDque también es a typedefa a void pointer.


Entonces, cuando se trata de LPCTSTReso, podemos encontrar eso en los mismos documentos:

Se define como LPCWSTRsi UNICODEse define o de LPCSTRotra manera.

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

Espero que esto ayude como guía sobre cómo entender los usos de typedefslos tipos de datos de Windows que se pueden encontrar en el Win32 API.

Francis Cugler
fuente
Muchos de los tipos de identificadores están más fuertemente tipados que solo ser HANDLEalias si activa la STRICTmacro. Cuál es el valor predeterminado en nuevos proyectos, creo.
Sebastian Redl
@SebastianRedl Podría ser; pero no estaba tratando de profundizar demasiado en la API y la rigurosidad de los aspectos fuertemente tipados del lenguaje. Fue más una visión general de la API Win32 y sus tipos de datos mediante el uso de typedefs ...
Francis Cugler