在用C++編寫的Windows應用程序中使用TreeView Common Control時,遇到了一個奇怪的問題,並且通過Windows API(無MFC或其他!): 如果加載了ComCtl32.dll的6.0版本(通過使用清單來說服鏈接器這樣做),則僅發送兩個重要通知TVN_ITEMCHANGED和TVN_ITEMCHANGING(自Windows Vista以來可用)和如果使用Unicode字符集。 使用多字節字符集會導致上述兩個通知消失。 使用Unicode和版本5.82 ComCtl32.dll產生相同的結果。順便說一下,我採用了Windows 7 x64和Visual Studio 2010。Windows TreeView常見控件通知和多字節字符集的問題
下面,您會找到一個「最小」(> 180行代碼:/)工作示例。使用Unicode字符集(配置屬性>常規>字符集)在Visual Studio 2010下編譯可使程序按預期工作,但使用多字節字符集會使TVN_ITEMCHANGED和TVN_ITEMCHANGING消失。無論如何還有其他通知。
我忽略了一些事情還是遇到了公共控件實現中的錯誤?我真誠地希望這是我以前的猜測,我非常感謝你對此事的回答和想法!
最好的問候, D.費爾德曼
#include <Windows.h>
#include <CommCtrl.h>
#include <iostream>
#pragma comment(linker, "\"/manifestdependency:type='win32'\
name='Microsoft.Windows.Common-Controls'\
version='6.0.0.0'\
processorArchitecture='*'\
publicKeyToken='6595b64144ccf1df'\
language='*'\"")
HINSTANCE g_hInst = 0;
HWND hwndTV_ = 0;
bool setupTreeView(HWND hwnd)
{
RECT rc = {0};
GetClientRect(hwnd, &rc);
DWORD style = WS_CHILD | WS_VISIBLE | WS_OVERLAPPED | TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT;
hwndTV_ = CreateWindowEx(WS_EX_CLIENTEDGE, WC_TREEVIEW, 0, style,
10, 10, (rc.right - rc.left) - 20, (rc.bottom - rc.top) - 20,
hwnd, (HMENU) 0xDF, g_hInst, 0);
if (! hwndTV_)
return false;
style |= TVS_CHECKBOXES;
SetWindowLong(hwndTV_, GWL_STYLE, style);
HIMAGELIST hil = ImageList_Create(24, 24, ILC_COLOR | ILC_COLOR32, 2, 0);
const int img1 = ImageList_AddIcon(hil, LoadIcon(0, IDI_QUESTION));
const int img2 = ImageList_AddIcon(hil, LoadIcon(0, IDI_INFORMATION));
SendMessage(hwndTV_, TVM_SETIMAGELIST, TVSIL_NORMAL, (LPARAM) hil);
TVINSERTSTRUCT tvis = {0};
tvis.hParent = TVI_ROOT;
tvis.hInsertAfter = TVI_ROOT;
tvis.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
tvis.item.cchTextMax = 5;
tvis.item.pszText = TEXT("root\0");
tvis.item.state = (2 << 12) | TVIS_EXPANDED;
tvis.item.stateMask = TVIS_STATEIMAGEMASK | TVIS_EXPANDED;
tvis.item.iImage = img1;
tvis.item.iSelectedImage = img2;
HTREEITEM hRoot = (HTREEITEM) SendMessage(hwndTV_, TVM_INSERTITEM, 0, (LPARAM) &tvis);
tvis.hParent = hRoot;
tvis.hInsertAfter = TVI_LAST;
tvis.item.cchTextMax = 7;
tvis.item.pszText = TEXT("item 1\0");
SendMessage(hwndTV_, TVM_INSERTITEM, 0, (LPARAM) &tvis);
tvis.item.pszText = TEXT("item 2\0");
SendMessage(hwndTV_, TVM_INSERTITEM, 0, (LPARAM) &tvis);
return true;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
LRESULT res = 0u;
bool handled = true;
switch (msg)
{
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_CREATE:
setupTreeView(hwnd);
break;
case WM_NOTIFY:
{
NMHDR* const nmhdr = (NMHDR*)lParam;
switch (nmhdr->code)
{
case NM_CUSTOMDRAW:
std::cout << "NM_CUSTOMDRAW\n";
break;
case NM_CLICK:
std::cout << "NM_CLICK\n";
break;
case TVN_ITEMCHANGING:
std::cout << "!!! TVN_ITEMCHANGING !!!\n";
break;
case TVN_ITEMCHANGED:
std::cout << "!!! TVN_ITEMCHANGED !!!\n";
break;
case TVN_SELCHANGED:
std::cout << "TVN_SELCHANGED\n";
break;
case TVN_SELCHANGING:
std::cout << "TVN_SELCHANGING\n";
break;
case TVN_ITEMEXPANDED:
std::cout << "TVN_ITEMEXPANDED\n";
break;
case TVN_ITEMEXPANDING:
std::cout << "TVN_ITEMEXPANDING\n";
break;
default:
break;
} // switch (
break;
}
default:
handled = false;
break;
} // switch (msg
if (! handled)
res = DefWindowProc(hwnd, msg, wParam, lParam);
return res;
}
int run(HINSTANCE hInst)
{
g_hInst = hInst;
WNDCLASSEX wndCls = {0};
wndCls.cbSize = sizeof(WNDCLASSEX);
wndCls.cbClsExtra = 0;
wndCls.cbWndExtra = 0;
wndCls.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wndCls.hCursor = LoadCursor(0, IDC_HAND);
wndCls.hIcon = LoadIcon(0, IDI_WINLOGO);
wndCls.hIconSm = LoadIcon(0, IDI_WINLOGO);
wndCls.hInstance = g_hInst;
wndCls.lpfnWndProc = WindowProc;
wndCls.lpszClassName = TEXT("TestWindowClass");
wndCls.lpszMenuName = 0;
wndCls.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
RegisterClassEx(&wndCls);
INITCOMMONCONTROLSEX cc = {0};
cc.dwSize = sizeof(INITCOMMONCONTROLSEX);
cc.dwICC = ICC_TREEVIEW_CLASSES;
InitCommonControlsEx(&cc);
HWND hwnd = CreateWindowEx(0, TEXT("TestWindowClass"), TEXT("Test TreeView"),
WS_VISIBLE | WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION, CW_USEDEFAULT,
CW_USEDEFAULT, 400, 300, NULL, NULL, hInst, 0);
MSG msg = {0};
for (BOOL res = TRUE; res != 0;)
{
res = GetMessage(&msg, 0, 0, 0);
if (res != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (msg.message == WM_QUIT)
res = 0;
}
HIMAGELIST hil = (HIMAGELIST) SendMessage(hwndTV_, TVM_GETIMAGELIST, (WPARAM) TVSIL_NORMAL, 0);
if (hil)
ImageList_Destroy(hil);
UnregisterClass(TEXT("TestWindowClass"), g_hInst);
return 0;
}
// Please build using /subsystem:console
int main(int /*argc*/, char** /*argv*/)
{
return run(GetModuleHandle(0));
}
唉唉,有時我不知道如何設法讓我的鞋子在早晨!非常感謝你,這非常解決它!儘管我不明白爲什麼剩餘的消息會像往常一樣出現,而TVN_ITEMCHANG(ED/ING)的行爲不同並且需要區分... – feldmann 2014-10-21 23:32:52
請參閱['TVM_GETUNICODEFORMAT'](http://msdn.microsoft.com/zh-cn/ us/library/windows/desktop/bb773730.aspx)和['TVM_SETUNICODEFORMAT'](http://msdn.microsoft.com/en-us/library/windows/desktop/bb773775.aspx)。 – 2014-10-21 23:53:13
我實際上已經發現了這兩條消息,並在發佈之前嘗試過,但它們不適用於TVN_ITEMCHANG(ED/ING)。經過睡眠並再次嘗試,我發現TVM_SETUNICODEFORMAT僅影響其他通知,如TVN_SELCHANG(ED/ING),但不會影響導致我的問題的兩個通知。雖然我會認爲這是一個錯誤,但它至少是一個(非常煩人的)不一致。無論如何,你的回答讓我找到解決方案,所以再次感謝! – feldmann 2014-10-22 09:16:18