LPCTSTR là gì?


37

cái gì LPCTSTRLPCTSTRgiống như (ví dụ HDC) và nó đại diện cho cái gì?



3
Đây là lý do tại sao chúng tôi chỉ yêu Microsoft.
zxcdw

2
Những "kiểu" đó luôn thể hiện sự ngạc nhiên, ví dụ như khi bạn làm LPCSTR p, q;và bạn muốn có const char *p, *q;. Bạn có thể từ chối sử dụng chúng?
ott--

9
Một sự gớm ghiếc.
Thomas Eding

2
Chuyển 64 bit của ứng dụng 32 bit đòi hỏi kiến ​​thức về các thuật ngữ đó
trao đổi quá mức

Câu trả lời:


76

Trích dẫn Brian Kramer trên các diễn đàn MSDN

LPCTSTR= L ‌ong P ‌ con trỏ tới C ‌onst T ‌CHAR STR ‌ing (Đừng lo lắng, một con trỏ dài giống như một con trỏ. Có hai hương vị của con trỏ dưới các cửa sổ 16 bit.)

Đây là bảng:

  • LPSTR = = char*
  • LPCSTR = = const char*
  • LPWSTR = = wchar_t*
  • LPCWSTR = = const wchar_t*
  • LPTSTR= char* or wchar_t*tùy thuộc vào_UNICODE
  • LPCTSTR= const char* or const wchar_t*tùy thuộc vào_UNICODE

29
Mỗi lần nhìn thấy tên loại đó tôi cảm thấy như co rúm lại. Có điều gì đó về nó làm tôi không thoải mái. (+1 BTW)
Donal Fellows

2
Khi nào tôi nên sử dụng loại con trỏ này?
Florian Margaine

@FlorianMargaine Khi một API cho bạn biết. Chỉ cần sử dụng các loại 'phù hợp' cho đến lúc đó
James

1
được cảnh báo, có rất nhiều cảnh báo cần lưu ý ở đây. wchar_t là loại 16 bit, nhưng có thể được sử dụng để lưu trữ cả ký tự unicode được mã hóa ucs2 và utf-16. utf-16 có thể sử dụng nhiều wchar_t để mã hóa một chữ cái duy nhất, ucs2 chỉ hỗ trợ một tập hợp con của ký tự unicode. Những hàm API nào bạn cần gọi cũng phụ thuộc vào mã hóa được sử dụng.
Michael Shaw

2
Tệ nhất là DWORD, trước đây là một từ kép 32 bit, nhưng ngày nay là một nửa từ 32 bit :-)
gnasher729

6

Không cần phải sử dụng bất kỳ loại nào liên quan đến TCHAR.

Các loại đó, tất cả các loại cấu trúc sử dụng chúng và tất cả các chức năng liên quan được ánh xạ tại thời điểm biên dịch thành phiên bản ANSI hoặc UNICODE (dựa trên cấu hình dự án của bạn). Các phiên bản ANSI thường có chữ A được gắn vào cuối tên và các phiên bản unicode nối thêm W. Bạn có thể sử dụng chúng một cách rõ ràng nếu bạn thích. MSDN sẽ lưu ý điều này khi cần thiết, ví dụ, nó liệt kê một hàm MessageBoxInirectA và MessageBoxInirectW tại đây: http://msdn.microsoft.com/en-us/l Library / windows / desktop / ms645511 (v = vs85) .aspx

Trừ khi bạn đang nhắm mục tiêu Windows 9x, thiếu triển khai nhiều chức năng unicode, không cần sử dụng các phiên bản ANSI. Nếu bạn đang nhắm mục tiêu Windows 9x, bạn có thể sử dụng TCHAR để xây dựng nhị phân ansi và unicode từ cùng một cơ sở mã, miễn là mã của bạn không đưa ra giả định nào về việc TCHAR là char hay wchar.

Nếu bạn không quan tâm đến Windows 9x, tôi khuyên bạn nên định cấu hình dự án của mình là unicode và coi TCHAR giống hệt với WCHAR. Bạn có thể sử dụng rõ ràng các chức năng và loại W nếu bạn thích, nhưng miễn là bạn không có kế hoạch chạy dự án của mình trên Windows 9x, điều đó không thực sự quan trọng.


0

Các loại này được ghi lại tại Windows Data Type trên MSDN:

LPCTSTR

Một LPCWSTRnếu UNICODEđược định nghĩa, một LPCSTRcách khác. Để biết thêm thông tin, hãy xem Kiểu dữ liệu Windows cho Chuỗi.

Loại này được khai báo trong WinNT.h như sau:

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

LPCWSTR

Một con trỏ tới một chuỗi ký tự Unicode 16 bit không có ký tự kết thúc. Để biết thêm thông tin, hãy xem Bộ ký tự được sử dụng bởi phông chữ.

Loại này được khai báo trong WinNT.h như sau:

typedef CONST WCHAR *LPCWSTR;

HDC

Một xử lý cho một bối cảnh thiết bị (DC).

Loại này được khai báo trong WinDef.h như sau:

typedef HANDLE HDC;

0

Tôi biết rằng câu hỏi này đã được hỏi cách đây khá lâu và tôi không cố gắng trả lời trực tiếp câu hỏi ban đầu chính xác, nhưng vì Q / A cụ thể này có một đánh giá khá tốt tôi muốn thêm một chút ở đây cho độc giả tương lai. Điều này phải làm cụ thể hơn với Win32 API typedefsvà làm thế nào để hiểu chúng.

Nếu bất cứ ai đã từng thực hiện bất kỳ chương trình Windows nào trong kỷ nguyên của các máy 32 bit từ Windows 95 cho đến Windows 7-8, họ sẽ hiểu và biết rằng phần mềm Win32 APInày được tải typedefsvà phần lớn các chức năng và cấu trúc của chúng sẽ được lấp đầy và được sử dụng dựa nhiều vào chúng.


Đây là một chương trình windows cơ bản để trình diễ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;
}

Đây chỉ là mã đủ để kết xuất một ứng dụng windows. Đây là thiết lập cơ bản nhất để khởi tạo các thuộc tính tối thiểu để hiển thị một cửa sổ cơ bản và như bạn có thể thấy nó đã được tải typedefstừ Win32 api.


Chúng ta hãy phá vỡ nó bằng cách xem xét các hàm WinMainInitWindowsAppchức năng: Điều đầu tiên là các tham số của hàm HINSTANCEPSTR:

WinMainchấp nhận một HINSTANCEđối tượng trong khi InitWindowsAppchấp nhận hai HINSTANCEđối tượng một đối tượng PSTR hoặc một số typedefchuỗi khác và int.

Tôi sẽ sử dụng InitWindowsApphàm ở đây vì nó sẽ đưa ra mô tả về đối tượng trong cả hai hàm.

Cái đầu tiên HINSTANCEđược định nghĩa là H andle to INSTANCE và đây là cái được sử dụng phổ biến nhất cho ứng dụng. Cái thứ hai là cái khác HANDLEvới INSTANCE trước đây hiếm khi được sử dụng nữa. Nó được giữ xung quanh cho mục đích kế thừa để không phải thay đổi WinMain()chữ ký hàm sẽ phá vỡ nhiều ứng dụng đã tồn tại trong quy trình. Tham số thứ ba là P ointer to STR ing.

Vì vậy, chúng ta phải hỏi bản thân của chúng ta là HANDLEgì? Nếu chúng ta tìm trong các Win32 APItài liệu tìm thấy ở đây: Các kiểu dữ liệu Windows, chúng ta có thể dễ dàng tra cứu và thấy rằng nó được định nghĩa là:

Một tay cầm cho một đối tượng. Loại này được khai báo trong WinNT.h như sau:

typedef PVOID HANDLE; 

Bây giờ chúng tôi có một cái khác typedef. Là PVOIDgì Chà điều đó là hiển nhiên nhưng hãy tìm kiếm điều đó trong cùng một bảng ...

Một con trỏ đến bất kỳ loại. Điều này được khai báo trong WinNT.h

typedef void *PVOID;

A HANDLEđược sử dụng để khai báo nhiều đối tượng trong những Win32 APIđiều như:

  • HKEY - Một tay cầm để đăng ký khóa. Được khai báo trong WinDef.h
    • typdef HANDLE HKEY;
  • HKL - Một tay cầm để nhận dạng miền địa phương. Được khai báo trong WinDef.h
    • typdef HANDLE HKL;
  • HMENU - Một tay cầm để một menu. Được khai báo trong WinDef.h
    • typdef HANDLE HMENU;
  • HPEN - Một tay cầm bút. Được khai báo trong WinDef.h
    • typedef HANDLE HPEN;
  • HWND - Một tay cầm để một cửa sổ. Được khai báo trong WinDef.h
    • typedef HANDLE HWND;
  • ... và vân vân chẳng hạn như HBRUSH, HCURSOR, HBITMAP, HDC, HDESK,, vv

Đây là tất cả những typedefsgì được khai báo sử dụng a typedeflà a HANDLEHANDLEchính nó được khai báo là a typedeftừ a PVOIDcũng là typedefa void pointer.


Vì vậy, khi nói đến LPCTSTRchúng ta có thể tìm thấy điều đó trong cùng một tài liệu:

Nó được định nghĩa là LPCWSTRnếu UNICODEđược định nghĩa hoặc LPCSTRkhác.

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

Vì vậy, hy vọng điều này sẽ giúp ích như một hướng dẫn về cách hiểu cách sử dụng typedefsđặc biệt với các Kiểu dữ liệu Windows có thể tìm thấy trong Win32 API.


Nhiều loại tay cầm được gõ mạnh hơn là HANDLEbí danh nếu bạn kích hoạt STRICTmacro. Đó là mặc định trong các dự án mới, tôi nghĩ.
Sebastian Redl

@SebastianRedl Nó có thể; nhưng tôi đã không cố gắng đi sâu vào quá nhiều API và sự nghiêm ngặt của các khía cạnh được đánh máy mạnh mẽ của ngôn ngữ. Đây là phần tổng quan về API Win32 và các kiểu dữ liệu của nó bằng cách sử dụng typedefs ...
Francis Cugler
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.