我正在尝试更改列表视图控件的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;
}
注意我尝试使用SetWindowSubclass()
添加wndproc,但发生错误:
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]
答案 0 :(得分:3)
使用SetWindowLongPtr(GWLP_WNDPROC)
对窗口过程进行子类化时,它将返回正在替换的上一个窗口过程。您的子类过程必须使用CallWindowProc()
而不是DefWindowProc()
将未处理的消息传递给之前的过程。这在documentation:
使用
SetWindowLongPtr
索引调用GWLP_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: