![](/img/trans.png)
[英]PlaySound() keeps playing my .wav after WM_DESTROY and a DrawText Issue
[英]Is my subclassing Common Controls tooltip destroying itself in WM_DESTROY before I can?
下面的程序創建一個帶有Common Controls工具提示的窗口,該工具提示將其子類化。 當我得到WM_DESTROY
,我本能地決定銷毀該工具提示,因為WM_DESTROY
在子窗口(並且我也假定也擁有窗口)被銷毀之前出現 ,但DestroyWindow()
失敗,返回最后一個錯誤1400( ERROR_INVALID_WINDOW_HANDLE
)。 (在wine上,它返回5( ERROR_ACCESS_DENIED
)。我假設這是wine的錯誤,要么錯誤地設置了最后一個錯誤,要么根本不設置最后一個錯誤;我可以稍后再提交。)
我已經在Windows XP 32位和Windows 7 64位上進行了測試,同時使用了Common Controls 5和6(下面使用了命令行“標志”),並在Ubuntu 14.10和15.04 beta上進行了測試。
如果工具提示正在自我毀滅,該怎么辦? 我應該僅僅依靠這種行為嗎? 還是應該WM_DESTROY
工具提示並自己處理WM_DESTROY
? (兩個相互繼承的窗口會引起問題嗎?)
謝謝。
// 31 march-2 april 2015
#define UNICODE
#define _UNICODE
#define STRICT
#define STRICT_TYPED_ITEMIDS
#define CINTERFACE
// get Windows version right; right now Windows XP
#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
#define _WIN32_WINDOWS 0x0501 /* according to Microsoft's winperf.h */
#define _WIN32_IE 0x0600 /* according to Microsoft's sdkddkver.h */
#define NTDDI_VERSION 0x05010000 /* according to Microsoft's sdkddkver.h */
#include <windows.h>
#include <commctrl.h>
#include <windowsx.h>
#include <stdio.h>
#include <stdlib.h>
void die(char *why)
{
fprintf(stderr, "error %s: %I32u\n", why, GetLastError());
abort();
}
HWND tooltip = NULL;
LRESULT CALLBACK wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CREATESTRUCT *cs = (CREATESTRUCT *) lParam;
TOOLINFOW ti;
switch (uMsg) {
case WM_CREATE:
tooltip = CreateWindowExW(WS_EX_TOOLWINDOW,
TOOLTIPS_CLASSW, L"",
WS_POPUP | TTS_NOPREFIX,
0, 0,
0, 0,
hwnd, NULL, cs->hInstance, NULL);
if (tooltip == NULL)
die("creating tooltip");
ZeroMemory(&ti, sizeof (TOOLINFOW));
ti.cbSize = TTTOOLINFOW_V2_SIZE;
ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS | TTF_TRANSPARENT;
ti.hwnd = hwnd;
ti.uId = (UINT_PTR) hwnd;
ti.hinst = cs->hInstance;
ti.lpszText = L"this is a tooltip! wow!";
if (SendMessageW(tooltip, TTM_ADDTOOL, 0, (LPARAM) (&ti)) == FALSE)
die("setting up tooltip");
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_DESTROY:
if (DestroyWindow(tooltip) == 0)
die("deleting tooltips");
break;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
void initCommonControls(BOOL);
int main(int argc, char *argv[])
{
BOOL comctl5;
WNDCLASSW wc;
HWND mainwin;
MSG msg;
comctl5 = FALSE;
if (argc > 1)
comctl5 = strcmp(argv[1], "comctl5") == 0;
initCommonControls(comctl5);
ZeroMemory(&wc, sizeof (WNDCLASSW));
wc.lpszClassName = L"mainwin";
wc.lpfnWndProc = wndproc;
wc.hIcon = LoadIconW(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
wc.hInstance = GetModuleHandle(NULL);
if (RegisterClassW(&wc) == 0)
die("registering main window class");
mainwin = CreateWindowExW(0,
L"mainwin", L"Main Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, GetModuleHandle(NULL), NULL);
if (mainwin == NULL)
die("creating main window");
ShowWindow(mainwin, SW_SHOWDEFAULT);
UpdateWindow(mainwin);
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
// MSDN doesn't list a constant that only includes tooltips but says this and a few others do
#define wantedICCClasses (ICC_BAR_CLASSES)
static ULONG_PTR comctlManifestCookie;
static HMODULE comctl32;
// note that this is an 8-bit character string we're writing; see the encoding clause
static const char manifest[] = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n<assemblyIdentity\n version=\"1.0.0.0\"\n processorArchitecture=\"*\"\n name=\"CompanyName.ProductName.YourApplication\"\n type=\"win32\"\n/>\n<description>Your application description here.</description>\n<dependency>\n <dependentAssembly>\n <assemblyIdentity\n type=\"win32\"\n name=\"Microsoft.Windows.Common-Controls\"\n version=\"6.0.0.0\"\n processorArchitecture=\"*\"\n publicKeyToken=\"6595b64144ccf1df\"\n language=\"*\"\n />\n </dependentAssembly>\n</dependency>\n</assembly>\n";
void initCommonControls(BOOL comctl5)
{
WCHAR temppath[MAX_PATH + 1];
WCHAR filename[MAX_PATH + 1];
HANDLE file;
DWORD nExpected, nGot;
ACTCTX actctx;
HANDLE ac;
INITCOMMONCONTROLSEX icc;
FARPROC f;
// this is listed as WINAPI in both Microsoft's and MinGW's headers, but not on MSDN for some reason
BOOL (*WINAPI ficc)(const LPINITCOMMONCONTROLSEX);
if (!comctl5) {
if (GetTempPathW(MAX_PATH + 1, temppath) == 0)
die("getting temporary path for writing manifest file");
if (GetTempFileNameW(temppath, L"manifest", 0, filename) == 0)
die("getting temporary filename for writing manifest file");
file = CreateFileW(filename, GENERIC_WRITE,
0, // don't share while writing
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file == NULL)
die("creating manifest file");
nExpected = (sizeof manifest / sizeof manifest[0]) - 1; // - 1 to omit the terminating null character)
if (WriteFile(file, manifest, nExpected, &nGot, NULL) == 0)
die("writing manifest file");
if (nGot != nExpected)
die("short write to manifest file");
if (CloseHandle(file) == 0)
die("closing manifest file (this IS an error here because not doing so will prevent Windows from being able to use the manifest file in an activation context)");
ZeroMemory(&actctx, sizeof (ACTCTX));
actctx.cbSize = sizeof (ACTCTX);
actctx.dwFlags = ACTCTX_FLAG_SET_PROCESS_DEFAULT;
actctx.lpSource = filename;
ac = CreateActCtx(&actctx);
if (ac == INVALID_HANDLE_VALUE)
die("creating activation context for synthesized manifest file");
if (ActivateActCtx(ac, &comctlManifestCookie) == FALSE)
die("activating activation context for synthesized manifest file");
}
ZeroMemory(&icc, sizeof (INITCOMMONCONTROLSEX));
icc.dwSize = sizeof (INITCOMMONCONTROLSEX);
icc.dwICC = wantedICCClasses;
comctl32 = LoadLibraryW(L"comctl32.dll");
if (comctl32 == NULL)
die("loading comctl32.dll");
f = GetProcAddress(comctl32, "InitCommonControlsEx");
if (f == NULL)
die("loading InitCommonControlsEx()");
ficc = (BOOL (*WINAPI)(const LPINITCOMMONCONTROLSEX)) f;
if ((*ficc)(&icc) == FALSE)
die("initializing Common Controls (comctl32.dll)");
}
工具提示沒有WS_CHILD樣式。 所有此類窗口在所有者窗口收到WM_DESTROY之前都已被完全銷毀。 結果是DestroyWindow(tooltip)並返回錯誤-ERROR_INVALID_WINDOW_HANDLE
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.