2016-08-30 17 views
3

我想改變一個列表視圖控件的Wndproc,所以wndproc中的第一個參數返回控制句柄接收消息,問題是當我改變它其他功能停止工作(我不能插入列或物品了),是不是我需要改變或爲了恢復使用相同的WndProc,以保持對所有的控件如何更改列表視圖控件的WndProc

WNDPROC同所有控件:

LRESULT CALLBACK staticWndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam){ 
    std::cout << (int)hwnd << " control received msg:" << uMsg << std::endl; //This must work 
    //event = { msg:uMsg, target:(int)hwnd, x:0, y:0, button:0, key:0 }; 
    switch (uMsg){ 
     case WM_DESTROY: 
      std::cout << "window says bye " << std::endl; 
      PostQuitMessage(WM_QUIT); 
      break; 
     default: 
      //msghandlercall(event); //this is handled not in c++ 
      return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    } 
    return 0; 
} 

打電話來SetWindowLongPtr(handle, GWLP_WNDPROC, (LONG_PTR)staticWndProc);後插入消息不起作用默認

int createColumn(HWND listhandle, int indexCol, char *Text, int width){ 
    LVCOLUMN lvc={0}; 
    lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; 
    lvc.fmt = LVCFMT_LEFT; 
    lvc.cx = width; 
    lvc.pszText = Text; 
    lvc.iSubItem = indexCol; 
    //return ListView_InsertColumn(listhandle, indexCol, &lvc); 
    SendMessage(listhandle,LVM_INSERTCOLUMN,indexCol,(LPARAM)&lvc); 
    return 1; 
} 
void createColumns(HWND listhandle, std::vector<LPSTR> columns){ 
    for(int i=0; i<columns.size(); i++) createColumn(listhandle, i, columns[i], 50); 
} 
int createItem(HWND listhandle, const std::vector<LPSTR>& row){ 
    LVITEM lvi = {0}; 
    //lvi.mask = LVIF_TEXT; 
    // lvi.pszText = row[0]; 
    int ret = ListView_InsertItem(listhandle, &lvi); 
    if(ret>-1) for(unsigned i=0; i<row.size(); i++) 
     ListView_SetItemText(listhandle, ret, i, row[i]); 
    return ret; 
} 
HWND createList(int parenthandle=0){ 
    if(parenthandle==0) parenthandle=(int)GetDesktopWindow(); 
    HWND handle = CreateWindow(WC_LISTVIEW, "",WS_VISIBLE|WS_BORDER|WS_CHILD | LVS_REPORT | LVS_EDITLABELS, 
          10, 10, 300, 100, (HWND)parenthandle, /*(HMENU)ID_LIST*/NULL, GetModuleHandle(NULL), 0); 
    if(!handle){ std::cerr << "Failed to create list\n"; return 0; } 
    SetWindowLongPtr(handle, GWLP_WNDPROC, (LONG_PTR)staticWndProc); 
    ListView_SetExtendedListViewStyle(handle, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER); 
    createColumns(handle,{"col1","col2","col3"}); 
    createItem(handle,{"item1.1","item1.2","item1.3","item1.4"}); 
    createItem(handle,{"item2.1","item2.2","item2.3","item2.4"}); 
    return handle; 
} 

注意我嘗試添加的WndProc與SetWindowSubclass()但出現錯誤: error C2664: 'BOOL IsolationAwareSetWindowSubclass(HWND,SUBCLASSPROC,UINT_PTR,DWORD_PTR)': cannot convert argument 2 from 'LRESULT (__cdecl *)(HWND,UINT,WPARAM,LPARAM)' to 'SUBCLASSPROC' [build\binding.vcxproj]

+1

你只使用WNDPROC處理銷燬消息 - 所以這是唯一的想你可以使用該WNDPROC。您可能需要向WNDPROC添加更多消息。 –

+1

您需要獲取控件的現有回調,並調用不是「DefWindowProc」的默認情況下的語句。 –

+2

調用DefWindowProc()爲子類窗口實際*繞過窗口的WndProc()。所以很確定,很多東西停止工作。您必須調用* original * WndProc,這是您應該首先使用GetWindowLongPtr檢索的那個。這當然意味着你不能使用一個WndProc來銷燬它們。嘗試下降[在成功的坑中](https://msdn.microsoft。COM/EN-US /庫/窗/桌面/ bb762102(V = vs.85)的.aspx)。 –

回答

3

當你繼承使用SetWindowLongPtr(GWLP_WNDPROC)窗口過程,則返回被替換先前的窗口過程。您的子類程序必須使用CallWindowProc()而不是DefWindowProc()將未處理的消息傳遞到之前的程序。這在documentation表述爲多:

調用SetWindowLongPtrGWLP_WNDPROC指數創建用於創建窗口的窗口類的子類。應用程序可以繼承一個系統類,但不應該繼承由另一個進程創建的窗口類。 SetWindowLongPtr函數通過更改與特定窗口類關聯的窗口過程來創建窗口子類,導致系統調用新窗口過程而不是先前窗口過程。 應用程序必須通過調用CallWindowProc將任何未由新窗口過程處理的消息傳遞給上一個窗口過程。這允許應用程序創建一系列窗口過程

你沒有這樣做,這就是你的代碼失敗的原因。

試試這個:

WNDPROC prevWndProc; 

LRESULT CALLBACK staticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
{ 
    //... 
    return CallWindowProc(prevWndProc, hwnd, uMsg, wParam, lParam); 
} 

HWND createList(HWND parenthandle = NULL) 
{ 
    if (!parenthandle) parenthandle = GetDesktopWindow(); 

    HWND handle = CreateWindow(..., parenthandle, ...); 
    if (!handle) { 
     std::cerr << "Failed to create list\n"; 
     return NULL; 
    } 

    prevWndProc = (WNDPROC) SetWindowLongPtr(handle, GWLP_WNDPROC, (LONG_PTR)staticWndProc); 
    if (!prevWndProc) { 
     std::cerr << "Failed to subclass list\n"; 
     DestroyWindow(handle); 
     return NULL; 
    } 

    ... 

    return handle; 
} 

話雖這麼說,你真的不應該使用SetWindowLongPtr(GWLP_WNDPROC)可言。確切的原因是不安全的(等等)。您應該使用SetWindowSubclass()代替:

LRESULT CALLBACK staticSubClass(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) 
{ 
    //... 

    if (uMsg == WM_NCDESTROY) { 
     // NOTE: this requirement is NOT stated in the documentation, 
     // but it is stated in Raymond Chen's blog article... 
     RemoveWindowSubclass(hWnd, staticSubClass, uIdSubclass); 
    } 

    return DefSubclassProc(hWnd, uMsg, wParam, lParam); 
} 

HWND createList(HWND parenthandle = NULL) 
{ 
    if (!parenthandle) parenthandle = GetDesktopWindow(); 

    HWND handle = CreateWindow(..., parenthandle, ...); 
    if (!handle) { 
     std::cerr << "Failed to create list\n"; 
     return NULL; 
    } 

    if (!SetWindowSubclass(handle, staticSubClass, 1, 0)){ 
     std::cerr << "Failed to subclass list\n"; 
     DestroyWindow(handle); 
     return NULL; 
    } 

    ... 

    return handle; 
} 

查看MSDN瞭解更多詳細信息:

Subclassing Controls

Safer subclassing

+0

你說得對,就像魅力一樣。謝謝 – shuji