LPCTSTR คืออะไร


37

สิ่งที่เป็นLPCTSTRและLPCTSTRเหมือน (เช่นHDC) และสิ่งที่มันไม่ยืน?



3
นี่คือเหตุผลที่เรารัก Microsoft
zxcdw

2
บรรดา "ประเภท" มักจะแสดงความผิดเช่นเมื่อคุณทำและคุณต้องการที่จะมีLPCSTR p, q; const char *p, *q;คุณปฏิเสธที่จะใช้มันได้หรือไม่?
ott--

9
สิ่งที่น่ารังเกียจ
Thomas Eding

2
การพอร์ต 64 บิตของแอปพลิเคชัน 32 บิตต้องการความรู้เกี่ยวกับคำศัพท์ดังกล่าว
overexchange

คำตอบ:


76

การอ้างอิง Brian Kramer ในฟอรัม MSDN

LPCTSTR= Lอ่องP ointer กับC onst T CHAR STRไอเอ็นจี (ไม่ต้องกังวลตัวชี้ยาวเป็นเช่นเดียวกับตัวชี้. มีสองรสชาติของตัวชี้อยู่ภายใต้หน้าต่าง 16 บิต.)

นี่คือตาราง:

  • 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)
Donal Fellows

2
เมื่อใดฉันจึงควรใช้ตัวชี้ชนิดนี้?
Florian Margaine

@FlorianMargaine เมื่อ API แจ้งให้คุณทราบ เพียงแค่ใช้ประเภท 'เหมาะสม' จนกว่าจะถึงวันนั้น
James

1
ได้รับคำเตือนมีข้อควรระวังมากมายที่นี่ wchar_t เป็นชนิด 16 บิต แต่สามารถใช้เพื่อเก็บอักขระ unicode ที่เข้ารหัส ucs2 และ utf-16 utf-16 อาจใช้หลาย wchar_t เพื่อเข้ารหัสตัวอักษรเดียว ucs2 รองรับชุดย่อยของชุดอักขระ Unicode เท่านั้น ฟังก์ชัน API ใดที่คุณต้องการเรียกใช้ขึ้นอยู่กับการเข้ารหัสที่ใช้
Michael Shaw

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 จาก codebase เดียวกันตราบใดที่รหัสของคุณไม่มีข้อสันนิษฐานเกี่ยวกับ TCHAR ว่าเป็น char หรือ wchar

หากคุณไม่สนใจ Windows 9x ฉันขอแนะนำให้กำหนดค่าโครงการของคุณเป็น Unicode และใช้ TCHAR เหมือนกับ WCHAR คุณสามารถใช้ฟังก์ชั่น W และประเภทอย่างชัดเจนหากคุณต้องการ แต่ตราบใดที่คุณไม่ได้วางแผนที่จะรันโครงการของคุณบน Windows 9x มันไม่สำคัญเลย


0

ประเภทเหล่านี้มีการบันทึกไว้ที่Windows Data Typesบน MSDN:

LPCTSTR

LPCWSTRถ้าUNICODEมีการกำหนดเป็นLPCSTRอย่างอื่น สำหรับข้อมูลเพิ่มเติมดูประเภทข้อมูลของ Windows สำหรับสตริง

ประเภทนี้มีการประกาศใน WinNT.h ดังนี้

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

LPCWSTR

ตัวชี้ไปยังสายอักขระที่สิ้นสุดด้วยค่าคงที่ null อักขระ 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 นี่คือการตั้งค่าขั้นพื้นฐานที่สุดในการเริ่มต้นคุณสมบัติที่น้อยที่สุดเปลือยเพื่อแสดงหน้าต่างขั้นพื้นฐานและในขณะที่คุณสามารถเห็นมันจะเต็มไปแล้วกับการจากtypedefsWin32 api


ลองแยกย่อยโดยดูที่WinMainและInitWindowsAppฟังก์ชั่น: สิ่งแรกคือพารามิเตอร์ของฟังก์ชั่นHINSTANCEและPSTR:

WinMainยอมรับHINSTANCEวัตถุเดียวในขณะที่InitWindowsAppยอมรับHINSTANCEวัตถุสองชิ้นเป็นวัตถุ PSTR หรือtypedefสตริงอื่นและ int

ฉันจะใช้InitWindowsAppฟังก์ชั่นที่นี่เพราะมันจะให้คำอธิบายของวัตถุในทั้งสองฟังก์ชั่น

อันแรกHINSTANCEถูกกำหนดให้เป็นH andle กับINSTANCEและนี่คืออันที่ใช้กันมากที่สุดสำหรับแอปพลิเคชัน คนที่สองเป็นอีกหนึ่งHANDLEไปก่อนหน้านี้เช่นที่ไม่ค่อยถูกนำมาใช้อีกต่อไป มันถูกเก็บไว้รอบ ๆ เพื่อวัตถุประสงค์ดั้งเดิมเพื่อไม่ต้องเปลี่ยนWinMain()ลายเซ็นฟังก์ชันที่จะทำลายแอปพลิเคชันที่มีอยู่แล้วจำนวนมากในกระบวนการ พารามิเตอร์ที่สามคือP ointer ถึงSTR ing

ดังนั้นเราต้องถามตัวเองว่าอะไรคือ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ที่มีการประกาศใช้typedefซึ่งเป็นHANDLEและHANDLEตัวเองจะถูกประกาศเป็นtypedefจากPVOIDที่นี้ยังเป็นไปtypedefvoid pointer


ดังนั้นเมื่อพูดถึงLPCTSTRเราจะพบว่าในเอกสารเดียวกัน:

มันถูกกำหนดให้เป็นLPCWSTRถ้าUNICODEมีการกำหนดหรือLPCSTRมิฉะนั้น

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

เพื่อหวังว่านี้จะช่วยเป็นแนวทางที่จะเป็นวิธีที่จะเข้าใจความหมายของtypedefsโดยเฉพาะอย่างยิ่งกับประเภทของ Windows ข้อมูลWin32 APIที่สามารถพบได้ใน


ชนิดของจุดจับหลายประเภทถูกพิมพ์อย่างยิ่งกว่าเป็นHANDLEนามแฝงหากคุณเปิดใช้งานSTRICTแมโคร ซึ่งเป็นค่าเริ่มต้นในโครงการใหม่ฉันคิดว่า
Sebastian Redl

@SebastianRedl มันอาจจะเป็น; แต่ฉันไม่ได้พยายามเจาะลึกถึง API มากเกินไปและความเข้มงวดของภาษาที่พิมพ์ออกมาอย่างรุนแรง มันเป็นภาพรวมของ Win32 API และประเภทข้อมูลโดยการใช้ typedefs ...
Francis Cugler
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.