2016-08-22 13 views
7

पर एएनएसआई विंडो बदलता है SetWindowSubClass() एक एएनएसआई विंडो को यूनिकोड विधवा में बदलना चाहिए? इस व्यवहार के बारे में मुझे दस्तावेज, या वेब पर कुछ भी नहीं मिला।SetWindowSubclass UNICODE

मैं जांच एप्लिकेशन (full source) सिर्फ उदाहरण देकर स्पष्ट करने के लिए कैसे SetWindowSubclass (मेरा मानना ​​है कि) प्रभावित खिड़की ANSI से यूनिकोड के प्रकार बदल जाता है, के रूप में यह नहीं करना चाहिए बनाया! IsWindowUnicode() परिवर्तन की पुष्टि करता है।

program TwoWaySubclassing; 

{$apptype gui} 
{$R Generic.res}       

{ 
{ I created this test application just to illustrate how SetWindowSubclass() 
{ changes -- I believe -- the type of the affected window from ANSI to UNICODE, 
{ as it shouldn't! IsWindowUnicode() confirms that. 
{ 
{ The Delphi 7 (all ANSI) application has 2 edit controls: 
{ 1. The smaller, which is subclassed in 2 switchable ways (called Modes). 
{ 2. The bigger, like a memo, not subclassed. Just for dumping info. 
{ 3. A button for switching between modes, on-the-fly. 
{ 
{ The default subclassing Mode uses SetWindowLong (the classic way). 
{ When pressing the button, the edit control is subclassed via SetWindowSubclass. 
{ Pressing it again brings the edit control back to the default SetWindowLong mode. 
{ 
{ The main window (and all child controls) are created using the ANSI version 
{ of the API procedure, so the message handler should receive, in "lParam", 
{ a pointer to an ANSI text (along with the wm_SetText message), always! 
{ 
{ The problem is that's not happening when the edit control is subclassed using 
{ the SetWindowSubclass mode! SetWindowSubclass() simply changes the window 
{ from ANSI to UNICODE and starts sending a PWideChar(lParam) rather than the 
{ expected PAnsiChar(lParam). 
{ 
{ Once back to the default SetWindowLong mode, the window becomes ANSI again! 
{ Just run the application and try switching between modes. Look carefully at the 
{ detailed info shown in the bigger edit control. 
{ 
{ Screenshots: 
{ 1. http://imgh.us/mode1.png 
{ 2. http://imgh.us/mode2.png 
{ 
{ Environment: 
{ Windows 7 32-bit 
{ Delphi 7 (all-ANSI) 
{ 
{ Regards, 
{ Paulo França Lacerda 
} 

uses 
    Windows, 
    Messages, 
    SysUtils; 

type 
    UINT_PTR = Cardinal; 
    DWORD_PTR = Cardinal; 

    TSubClassProc = function (hWnd:HWND; uMsg:UINT; wParam:WPARAM; lParam:LPARAM; uIdSubclass:UINT_PTR; dwRefData:DWORD_PTR) :LRESULT; stdcall; 

    TSubMode = (
    subSetWindowLong, 
    subSetWindowSubclass); 

const 
    LtBool :Array[Boolean] of String = ('False', 'True'); 
    LtSubMode :Array[TSubMode] of String = ('SetWindowLong', 'SetWindowSubclass'); 

    strTextUsingPAnsiChar = 'ANSI Text in PAnsiChar(lParam)'; 
    strTextUsingPWideChar = 'UNICODE Text in PWideChar(lParam)'; 

const 
    cctrl = Windows.comctl32; 

function SetWindowSubclass (hWnd:Windows.HWND; pfnSubclass:TSubClassProc; uIdSubclass:UINT_PTR; dwRefData:DWORD_PTR) :BOOL; stdcall; external cctrl name 'SetWindowSubclass'; 
function RemoveWindowSubclass (hWnd:Windows.HWND; pfnSubclass:TSubClassProc; uIdSubclass:UINT_PTR) :BOOL;      stdcall; external cctrl name 'RemoveWindowSubclass'; 
function DefSubclassProc  (hWnd:HWND; uMsg:UINT; wParam:WPARAM; lParam:LPARAM) :LRESULT;         stdcall; external cctrl name 'DefSubclassProc'; 

var 
    wc :TWndClass; 
    Msg :TMsg; 

    hButton :HWnd; 
    hEdit :HWnd; 
    hEdit2 :HWnd; 
    hFont :HWnd; 
    hFont2 :HWnd; 

    hMainHandle :HWnd; 
    swl_OldProc :Pointer; // Default Procedure for Subclassing #1 (via SetWindowLong) 
    SubMode :TSubMode; 


procedure Release_Resources; 
begin 
    DestroyWindow (hButton); hButton := 0; 
    DestroyWindow (hEdit); hEdit := 0; 
    DestroyWindow (hEdit2); hEdit2 := 0; 
    DeleteObject (hFont); hFont := 0; 
    DeleteObject (hFont2); hFont2 := 0; 
end; 

procedure MsgBox (S:String); 
begin 
    MessageBox (hMainHandle, PChar(S), 'Information', mb_Ok or mb_IconInformation); 
end; 

procedure Reveal_Text (lParam:LPARAM); 
const 
    lf = #13#10; 
    lf2 = lf+lf; 
var 
    S :String; 
    AnsiTxt :String; 
    UnicTxt :String; 
    Remarks :Array[1..3] of String; 
begin 
    if IsWindowUnicode(hEdit) 
    then Remarks[1] := ' (Man! SetWindowSubclass changed it to Unicode!!)' 
    else Remarks[1] := ' (great! as designed)'; 

    AnsiTxt := PAnsiChar(lParam); 

    if (Length(AnsiTxt) = 1) 
    then Remarks[2] := ' (text is obviously truncated)' 
    else Remarks[2] := ' (text is healthy and is ANSI, as it should)'; 

    UnicTxt := PWideChar(lParam); 

    if (Pos('?',UnicTxt) > 0) 
    then Remarks[3] := ' (text is obviously garbaged)' 
    else Remarks[3] := ' (text is healthy, but I want it to be ANSI)'; 

    S := 
      'Subclassed using: ' 
    +lf +' '+LtSubMode[SubMode]+'()' 
    +lf2+ 'IsUnicodeWindow(hEdit)? ' 
    +lf +' '+LtBool[IsWindowUnicode(hEdit)] 
    +lf +  Remarks[1] 
    +lf2+'PAnsiChar(lParam):' 
    +lf +' "'+PAnsiChar(lParam)+'"' 
    +lf +  Remarks[2] 
    +lf2+ 'PWideChar(lParam):' 
    +lf +' "'+PWideChar(lParam)+'"' 
    +lf +  Remarks[3]; 

    SetWindowText (hEdit2, PChar(S)); 
end; 

function swl_EditWndProc (hWnd:HWnd; uMsg:UInt; wParam:WParam; lParam:LParam) :LResult; stdcall; 
begin 
    Result := CallWindowProc (swl_OldProc, hWnd, uMsg, wParam, lParam); 
    if (uMsg = wm_SetText) then Reveal_Text(lParam); 
end; 

function sws_EditWndProc (hWnd:HWND; uMsg:UINT; wParam:WPARAM; lParam:LPARAM; uIdSubclass:UINT_PTR; dwRefData:DWORD_PTR) :LRESULT; stdcall; 
begin 
    Result := DefSubclassProc (hWnd, uMsg, wParam, lParam); 
    if (uMsg = wm_SetText) then Reveal_Text(lParam); 
end; 

procedure do_SetWindowSubclass; 
begin 
    if not SetWindowSubclass (hEdit, @sws_EditWndProc, 1, dword_ptr($1234{whatever})) 
    then RaiseLastOSError; 

    SubMode := subSetWindowSubclass; 
end; 

procedure undo_SetWindowSubclass; 
begin 
    if not RemoveWindowSubclass (hEdit, @sws_EditWndProc, 1) 
    then RaiseLastOSError; 

    SubMode := subSetWindowLong; // restored 
end; 

function AppWindowProc (hWnd:HWnd; uMsg:UInt; wParam:WParam; lParam:LParam) :LResult; stdcall; 
begin 
    case uMsg of 
    wm_Command: 
    begin 
     if (lParam = hButton) then 
     case SubMode of 
     subSetWindowLong: 
     begin 
      do_SetWindowSubclass; // now using SetWindowSubclass() 
      SetWindowText (hEdit, PChar(strTextUsingPWideChar)); 
      SetWindowText (hButton, PChar('Switch back to SetWindowLong mode')); 
     end; 

     subSetWindowSubclass: 
     begin 
      undo_SetWindowSubclass; // back to SetWindowLong() 
      SetWindowText (hEdit, PChar(strTextUsingPAnsiChar)); 
      SetWindowText (hButton, PChar('Switch to SetWindowSubclass mode')); 
     end; 
     end; 
    end; 

    wm_Destroy: 
    begin 
     Release_Resources; 
     PostQuitMessage (0); 
     Exit; 
    end; 
    end; 

    Result := DefWindowProc (hWnd, uMsg, wParam, lParam); 
end; 

var 
    W,H :Integer; 

begin 
    wc.hInstance  := hInstance; 
    wc.lpszClassName := 'ANSI_Wnd'; 
    wc.Style   := cs_ParentDC; 
    wc.hIcon   := LoadIcon(hInstance,'MAINICON'); 
    wc.lpfnWndProc := @AppWindowProc; 
    wc.hbrBackground := GetStockObject(white_brush); 
    wc.hCursor  := LoadCursor(0,IDC_ARROW); 

    RegisterClass(wc); // ANSI (using Delphi 7, so all Windows API is mapped to ANSI). 

    W := 500; 
    H := 480; 

    hMainHandle := CreateWindow ( // ANSI (using Delphi 7, so all Windows API is mapped to ANSI). 
    wc.lpszClassName,'2-Way Subclassing App', 
    ws_OverlappedWindow or ws_Caption or ws_MinimizeBox or ws_SysMenu or ws_Visible, 
    ((GetSystemMetrics(SM_CXSCREEN)-W) div 2), // vertically centered in screen 
    ((GetSystemMetrics(SM_CYSCREEN)-H) div 2), // horizontally centered in screen 
    W,H,0,0,hInstance,nil); 

    // create the fonts 
    hFont := CreateFont (-14,0,0,0,0,0,0,0, default_charset, out_default_precis, clip_default_precis, default_quality, variable_pitch or ff_swiss, 'Tahoma'); 
    hFont2:= CreateFont (-14,0,0,0,0,0,0,0, default_charset, out_default_precis, clip_default_precis, default_quality, variable_pitch or ff_swiss, 'Courier New'); 

    // create the edits 
    hEdit :=CreateWindowEx (WS_EX_CLIENTEDGE,'EDIT','some text', WS_VISIBLE or WS_CHILD or ES_LEFT or ES_AUTOHSCROLL,    10,35,W-40, 23,hMainHandle,0,hInstance,nil); 
    hEdit2:=CreateWindowEx (WS_EX_CLIENTEDGE,'EDIT','details', WS_VISIBLE or WS_CHILD or ES_LEFT or ES_AUTOHSCROLL or ES_MULTILINE,10,72,W-40,300,hMainHandle,0,hInstance,nil); 
    SendMessage(hEdit, WM_SETFONT,hFont, 0); 
    SendMessage(hEdit2,WM_SETFONT,hFont2,0); 

    // create the button 
    hButton:=CreateWindow ('Button','Switch to SetWindowSubclass mode', WS_VISIBLE or WS_CHILD or BS_PUSHBUTTON or BS_TEXT, 90,H-95,290,32,hMainHandle,0,hInstance,nil); 
    SendMessage(hButton,WM_SETFONT,hFont,0); 

    // subclass the Edit using the default method. 
    swl_OldProc := Pointer(GetWindowLong(hEdit,GWL_WNDPROC)); 
    SetWindowLong (hEdit,GWL_WNDPROC,Longint(@swl_EditWndProc)); 

    SubMode := subSetWindowLong; 
    SetWindowText (hEdit, PChar(strTextUsingPAnsiChar)); 

    // message loop 
    while GetMessage(Msg,0,0,0) do 
    begin 
    TranslateMessage(Msg); 
    DispatchMessage(Msg); 
    end; 
end. 

आवेदन 2 संपादन नियंत्रण है:

  1. छोटे से एक है, जो 2 switchable तरीकों से subclassed है (यहाँ मोड कहा जाता है)।
  2. बड़ा ज्ञापन, एक ज्ञापन की तरह, उपclassed नहीं। बस डंपिंग जानकारी के लिए।

मोड के बीच स्विच करने के लिए एक बटन भी है।

डिफ़ॉल्ट उपवर्गीकरण मोड SetWindowLong() का उपयोग करता है (क्लासिक तरीका):

SetWindowLong mode

डेल्फी 2007 में और उसके पहले, मुख्य विंडो (और सभी बच्चे नियंत्रण) Win32 एपीआई के एएनएसआई संस्करण का उपयोग कर बनाई गई हैं प्रक्रियाओं, इसलिए संदेश हैंडलर (उपclassed नियंत्रण के) को एएनएसआई पाठ प्राप्त करना चाहिए (WM_SETTEXT संदेश के साथ), हमेशा!

समस्या ऐसा नहीं हो रहा है जब संपादन नियंत्रण SetWindowSubclass() का उपयोग करके उपclassed है! SetWindowSubClass()एएनएसआई से यूनिकोड में विंडो बदलता है और यह अपेक्षित एएनएसआई टेक्स्ट की बजाय यूनिकोड टेक्स्ट प्राप्त करना शुरू करता है।

बटन दबाने SetWindowSubclass() के माध्यम से संपादित करें नियंत्रण उपवर्गों:

SetWindowSubclass mode

बटन दबाने से फिर से SetWindowLong() के माध्यम से संपादित करें नियंत्रण उपवर्गों।

एक बार वापस SetWindowLong() मोड, संपादित नियंत्रण स्वचालित रूप से फिर से एएनएसआई पाठ प्राप्त करता है:

SetWindowLong mode

बस आवेदन चलाने के लिए और मोड के बीच स्विच करने का प्रयास करें। बड़े संपादन नियंत्रण में दिखाए गए विस्तृत जानकारी पर ध्यान से देखें।

बस स्पष्ट होने के लिए: मुझे लगता है कि यह एक माइक्रोसॉफ्ट बग है। हालांकि, अगर यह एक "फीचर" है, तो क्या कोई मुझे संबंधित दस्तावेज में ले जा सकता है? मैं इसे कहीं भी नहीं मिला।

+1

क्या आप 'SetWindowSubClassA' या' SetWindowSubClassW' को कॉल कर रहे हैं? –

+0

@ जोनाथन पॉटर: जैसा कि मैंने उल्लेख किया है, डेल्फी 7 हमेशा एपीआई के एएनएसआई संस्करण में मैप करता है। मैंने ए/डब्ल्यू स्वाद के साथ आने वाले सभी एपीआई को स्पष्ट कॉल के साथ भी परीक्षण किया। 'SetWindowSubClassA' मैंने लिंक करने का प्रबंधन नहीं किया था। क्या यह अस्तित्व में है? जब इसे लिंक करने का प्रयास करते समय मुझे संकलन त्रुटि मिली। –

+2

@ जोनाथनपोटर: मुझे नहीं लगता कि ए और डब्ल्यू संस्करण हैं। दस्तावेज उनका उल्लेख नहीं करता है, और फ़ंक्शन एक स्ट्रिंग नहीं लेता है, इसलिए कोई स्पष्ट कारण नहीं है कि क्यों होगा। –

उत्तर

11

MSDN के अनुसार:

Subclassing Controls Using ComCtl32.dll version 6

नोट ComCtl32.dll संस्करण 6 यूनिकोड केवल है।कॉमसीटीएल 32 डीएल संस्करण 6 द्वारा समर्थित सामान्य नियंत्रण एएनएसआई विंडो प्रक्रियाओं के साथ उपclassed (या superclassed) नहीं होना चाहिए।

...

नोट सभी प्रक्रिया को पारित कर दिया तार यूनिकोड तार भले ही यूनिकोड एक पूर्वप्रक्रमक परिभाषा के रूप में निर्दिष्ट नहीं है कर रहे हैं।

तो ऐसा लगता है कि डिज़ाइन किया गया है।

comctl32.dll मेरे c:\windows\syswow64 फ़ोल्डर में संस्करण 6.1 है।

+0

मैन! आपको यह मिला। बहुत स्पष्ट जवाब! मैंने वहां इतने सारे लेख पढ़े कि मैंने याद किया कि जिसने आपको बताया था। मुझे लगता है कि मुझे अपने एएनएसआई विंडोज़ को उपclassing के क्लासिक SetWindowLong-way के साथ रहना होगा। :) –

+0

मुझे डर है। मुझे कोई विकल्प नहीं मिला। –

+0

यह जानने के लिए अच्छी जानकारी है, धन्यवाद। लेकिन क्या वास्तव में कोई फर्क पड़ता है कि एक उपclassed Ansi विंडो यूनिकोड संदेश प्राप्त करता है? आप जानते हैं कि वे यूनिकोड में होंगे, इसलिए यदि आप उन्हें अंसी के रूप में काम करने की ज़रूरत है तो आप उन्हें यूनिकोड से अंसी में बदल सकते हैं। लेकिन यूनिकोड के रूप में उनके साथ क्यों काम नहीं करते? और बीटीडब्लू, आपका ऐप comCtrl v6 का उपयोग नहीं करेगा जब तक कि इसे स्पष्ट रूप से प्रकट नहीं किया जाता है (उदाहरण के लिए दृश्य शैलियों को सक्षम करने के लिए)। –

संबंधित मुद्दे