In my code I have a message class that I would like to 'Find' from another process.
class MyWindow : public CWnd
{
public:
MyWindow::MyWindow(LPCTSTR pszClassName)
{
auto wcn = ::AfxRegisterWndClass(NULL);
auto created = this->CreateEx(0, wcn, pszClassName, 0, 0, 0, 0, 0, HWND_MESSAGE, 0);
}
};
Then somewhere in my main app.
...
auto pszClassName = _T("MyWindowClass");
auto wnd = new MyWindow(pszClassName);
auto p = FindWindow(pszClassName, nullptr); // = nullptr
// or using FindWindowExW( ... )
p = FindWindowExW(nullptr, nullptr, pszClassName, nullptr);// = nullptr
p = FindWindowExW(HWND_MESSAGE, nullptr, pszClassName, nullptr);// = nullptr
So, regardless what I do, I never seem to 'Find' the created window.
How can I create a window that can be 'Found' using FindWindow[Ex]
I'm using a VS2013 console app. I've modified your code slightly to create a normal window and a message-only window and find both their handles by class name.
Output:
Normal window=00000000003A06FE Message-only window=00000000001F06CA
FindWindow=00000000003A06FE
FindWindowEx=00000000003A06FE
FindWindowEx(HWND_MESSAGE,...)=00000000001F06CA
Code:
typedef std::basic_string<TCHAR> tstring;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
class MyWindow //: public CWnd
{
public:
tstring className;
HWND hwnd;
HWND hwndMsgOnly;
HWND find1;
HWND find2;
HWND find3;
MyWindow::MyWindow(LPCTSTR pszClassName)
{
className = pszClassName;
//auto wcn = ::AfxRegisterWndClass(NULL);
//auto created = this->CreateEx(0, wcn, pszClassName, 0, 0, 0, 0, 0, HWND_MESSAGE, 0);
// For a console app, `hInstance` is the instance of the program
HINSTANCE hInstance = GetModuleHandle(0);
WNDCLASSEX windowClass;
windowClass.lpszClassName = pszClassName;
windowClass.cbClsExtra = NULL;
windowClass.cbWndExtra = NULL;
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(150, 0, 0));
windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
windowClass.hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION));
windowClass.hIconSm = (HICON)LoadImage(NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON, 16, 16, NULL);
windowClass.hInstance = hInstance;
windowClass.lpfnWndProc = WindowProc;
windowClass.lpszMenuName = NULL;
windowClass.style = CS_VREDRAW | CS_HREDRAW;
RegisterClassEx(&windowClass);
hwnd = CreateWindowEx(NULL, pszClassName, _T("Basic Window"), WS_OVERLAPPEDWINDOW | WS_VISIBLE, 100, 100, 500, 500, NULL, NULL, hInstance, NULL);
hwndMsgOnly = CreateWindowEx(NULL, pszClassName, _T("Dummy name"), 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
}
};
void window_test(MyWindow & wnd)
{
LPCTSTR pszClassName = wnd.className.c_str();
wnd.find1 = FindWindow(pszClassName, nullptr); // = nullptr for OP version; okay for this version
// or using FindWindowExW( ... )
/**
HWND hwndParent is a handle to the parent window whose child windows are to be searched.
If hwndParent is NULL, the function uses the desktop window as the parent window.The function searches among windows that are child windows of the desktop.
If hwndParent is HWND_MESSAGE, the function searches all message-only windows.
**/
HWND hWndParent = nullptr;
wnd.find2 = FindWindowExW(hWndParent, nullptr, pszClassName, nullptr);// = nullptr for OP version; okay for this version
hWndParent = HWND_MESSAGE;
wnd.find3 = FindWindowExW(hWndParent, nullptr, pszClassName, nullptr);// = nullptr for OP version; finds the message-only window in this version
}
void main()
{
MyWindow wnd(_T("test_window"));
cout << "Normal window=" << wnd.hwnd << " Message-only window=" << wnd.hwndMsgOnly << endl;
window_test(wnd);
cout << "FindWindow=" << wnd.find1 << endl;
cout << "FindWindowEx=" << wnd.find2 << endl;
cout << "FindWindowEx(HWND_MESSAGE,...)=" << wnd.find3 << endl;
}
Related
I am in a sticky situation.
I'm messing around with Bitmaps and windows.
I followed this tutorial: https://learn.microsoft.com/en-us/windows/win32/gdi/capturing-an-image
I am basically taking multiple pictures of my desktop and displaying them into a window.
It works great as intended but after like a minute or 2 the window won't update and I can't find the error or why this is occurring.
Here is the code:
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
case WM_DESTROY: {
PostQuitMessage(0); // Exit the program if the window gets closed.
} break;
case WM_SIZE: {
} break;
}
return DefWindowProc(hWnd, message, wParam, lParam); // Handle any messages the switch statement didn't
}
HWND SpawnWindow() {
WNDCLASSEX WindowClass;
SecureZeroMemory(&WindowClass, sizeof(WNDCLASSEX));
WindowClass.cbClsExtra = NULL;
WindowClass.cbWndExtra = NULL;
WindowClass.cbSize = sizeof(WNDCLASSEX);
WindowClass.style = CS_HREDRAW | CS_VREDRAW;
WindowClass.lpfnWndProc = WinProc;
WindowClass.hInstance = NULL;
WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WindowClass.hIcon = LoadIcon(0, IDI_APPLICATION);
WindowClass.hIconSm = LoadIcon(0, IDI_APPLICATION);
WindowClass.hbrBackground = NULL;
WindowClass.lpszClassName = L"Class NAme";
WindowClass.lpszMenuName = L"Menu Name";
RegisterClassEx(&WindowClass);
return CreateWindowEx(NULL, L"Class Name", L"Window Title", WS_VISIBLE | WS_TILEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, NULL, NULL);
}
void DoMessages() {
MSG msg = {};
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
std::cout << msg.message << "\n";
}
int main() {
HWND WindowToGetPic = SpawnWindow();
HDC DesktopDC = GetDC(0);
HDC WindowDC = GetDC(WindowToGetPic);
if (!DesktopDC)
std::cout << "DC NULL!\n";
HDC TempDC = CreateCompatibleDC(DesktopDC);
HDC TempDCWindow = CreateCompatibleDC(WindowDC);
if (!TempDC)
std::cout << "TempDC NULL!\n";
while (true) {
/*
after calling CreateCompatibleDC you mus then call CreateCompatiableBitmap with the DC recieved
then call SelectObject
*/
HBITMAP hBitmap = CreateCompatibleBitmap(TempDC, 1920, 1080);/* screen res */
SelectObject(TempDC, hBitmap);
SetStretchBltMode(TempDC, HALFTONE);
RECT WindowDimensions;
GetClientRect(WindowToGetPic, &WindowDimensions);
if (!BitBlt(WindowDC, 0, 0, WindowDimensions.right - WindowDimensions.left, WindowDimensions.bottom - WindowDimensions.top, DesktopDC, 0, 0, SRCCOPY))
std::cout << "BitBlt ERROR\n";
DoMessages();
InvalidateRect(WindowHwnd, NULL, TRUE);
}
std::cin.ignore();
return 0;
}
If anyone could test this, or spot why the window doesn't update after a minute or two I would really appreciate it.
Thank you in advance!
I think you have spent all resources.
For example,
You create bitmap every cycle and don't release it.
You call SelectObject and don't return selected object to original state.
You have several resource leaks:
when you are done with an HDC returned by GetDC, call ReleaseDC
when you are done with an HDC returned by CreateCompatibleDC, call DeleteDC
when you are done with hBitmap, select the original bitmap back into the DC and call DeleteObject. The original bitmap is returned by SelectObject.
This is all covered in the documentation (Google will find it).
I was making a program that draws two lines and a circle in the window, for this I used Direct2D.
I was doing a program that draws two lines and a circle in the window. I noticed a problem and that is that when drawing a line of coordinates (100,200), (200,200), that line is not drawn in the pixels (100,200) and ( 200,200). I checked this by reading the coordinates of the mouse in the window and seeing if the line actually has the coordinates that I mentioned.
Do a little more research, and according to Microsoft, direct2d works with dpi and not physical pixels.
So is there a way to work directly with pixels like in Processing or Win32 where the position of the controls is expressed in physical pixels of the window.
#include <d2d1_3.h>
#include <d2d1_3helper.h>
#include <d3d11_1.h>
#include <dxgi1_6.h>
#include <string>
#pragma comment(lib,"d3d11")
#pragma comment(lib,"d2d1")
#pragma comment(lib,"dxgi")
#pragma warning(disable : 4996)
using namespace D2D1;
using namespace std;
template<typename Interface> void SafeRelease(Interface**);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInst
, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
UNREFERENCED_PARAMETER(hPrevInst);
UNREFERENCED_PARAMETER(lpCmdLine);
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINLOGO));
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = L"Demo_Wnd_Class";
wc.lpszMenuName = NULL;
wc.style = 0;
RegisterClass(&wc);
DWORD dwTopLevelWndStyle = WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME | WS_MAXIMIZEBOX);
RECT clientRc = { 0,0,640,480 };
AdjustWindowRect(&clientRc, dwTopLevelWndStyle, FALSE);
HWND hWnd = CreateWindow(L"Demo_Wnd_Class", L"Direct2DDemo", dwTopLevelWndStyle, CW_USEDEFAULT, CW_USEDEFAULT
, clientRc.right - clientRc.left, clientRc.bottom - clientRc.top, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, SW_SHOWDEFAULT);
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
ID3D11Device* d3dDevice;
IDXGIDevice* dxgiDevice = NULL;
D3D_FEATURE_LEVEL featureLevels[] = {
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1,
};
HRESULT hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_BGRA_SUPPORT, featureLevels
, 7, D3D11_SDK_VERSION, &d3dDevice, NULL, NULL);
if (SUCCEEDED(hr)) {
OutputDebugString(L"D3D11 Device created successful\n");
hr = d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
}
ID2D1Device6* d2dDevice = NULL;
ID2D1DeviceContext6* d2dDeviceContext = NULL;
IDXGIFactory2* dxgiFactory = NULL;
IDXGISwapChain1* dxgiSwapChain = NULL;
IDXGISurface *dxgiBackBufferSurface = NULL; // Back buffer
ID2D1Bitmap1* bmpTarget = NULL;
ID2D1SolidColorBrush* shapeBr = NULL;
DXGI_SWAP_CHAIN_DESC1 dscd;
dscd.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
dscd.BufferCount = 2;
dscd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
dscd.Flags = 0;
dscd.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
dscd.Height = 480;
dscd.SampleDesc.Count = 1;
dscd.SampleDesc.Quality = 0;
dscd.Scaling = DXGI_SCALING_NONE;
dscd.Stereo = FALSE;
dscd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
dscd.Width = 640;
if (SUCCEEDED(hr)) {
OutputDebugString(L"DXGI Device created successful\n");
hr = D2D1CreateDevice(dxgiDevice, CreationProperties(D2D1_THREADING_MODE_SINGLE_THREADED, D2D1_DEBUG_LEVEL_NONE, D2D1_DEVICE_CONTEXT_OPTIONS_NONE), (ID2D1Device**)&d2dDevice);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"D2D Device created successful\n");
hr = d2dDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, (ID2D1DeviceContext**)&d2dDeviceContext);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"D2D Device Context created successful\n");
hr = CreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, __uuidof(IDXGIFactory2), (void**)&dxgiFactory);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"DXGI Factory created successful\n");
hr = dxgiFactory->CreateSwapChainForHwnd(d3dDevice, hWnd, &dscd, NULL, NULL, &dxgiSwapChain);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"DXGI Swap Chain created successful\n");
hr = dxgiSwapChain->GetBuffer(0, __uuidof(IDXGISurface), (void**)&dxgiBackBufferSurface);
}
if (SUCCEEDED(hr)) {
hr = d2dDeviceContext->CreateBitmapFromDxgiSurface(dxgiBackBufferSurface, BitmapProperties1(D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),0,0), &bmpTarget);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"D2D Bitmap created successful\n");
d2dDeviceContext->SetTarget(bmpTarget);
hr = d2dDeviceContext->CreateSolidColorBrush(ColorF(ColorF::White), &shapeBr);
}
if (SUCCEEDED(hr)) {
OutputDebugString(L"D2D Solid Color Brush created successful\n");
d2dDeviceContext->SetUnitMode(D2D1_UNIT_MODE_PIXELS);
d2dDeviceContext->SetTransform(Matrix3x2F::Identity());
d2dDeviceContext->SetAntialiasMode(D2D1_ANTIALIAS_MODE::D2D1_ANTIALIAS_MODE_ALIASED);
}
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
d2dDeviceContext->BeginDraw();
d2dDeviceContext->Clear(ColorF(ColorF::ForestGreen));
d2dDeviceContext->DrawLine(Point2F(400, 0), Point2F(400, 400), shapeBr);
d2dDeviceContext->DrawLine(Point2F(200.0f, 320.0f), Point2F(400.0f, 320.0f), shapeBr);
d2dDeviceContext->DrawEllipse(D2D1::Ellipse(Point2F(300.0f, 300.0f), 10.0f, 10.0f), shapeBr);
POINT cursorPos;
GetCursorPos(&cursorPos);
ScreenToClient(hWnd,&cursorPos);
wstring dbgCursorPos = wstring(L"(MouseX: " + to_wstring(cursorPos.x) + L" MouseY: " + to_wstring(cursorPos.y) + L")\n");
OutputDebugString(dbgCursorPos.c_str());
d2dDeviceContext->EndDraw();
dxgiSwapChain->Present(1, 0);
}
}
SafeRelease(&d3dDevice);
SafeRelease(&dxgiBackBufferSurface);
SafeRelease(&dxgiDevice);
SafeRelease(&dxgiFactory);
SafeRelease(&dxgiSwapChain);
SafeRelease(&d2dDevice);
SafeRelease(&d2dDeviceContext);
SafeRelease(&bmpTarget);
SafeRelease(&shapeBr);
return 0;
}
template<typename Interface> void SafeRelease(Interface** ppInterface) {
if (*ppInterface) {
(*ppInterface)->Release();
(*ppInterface) = NULL;
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
if (Msg == WM_DESTROY) {
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
I created sample to check tooltip control. Here is a little bit messy program, which creates window, button and registers for button tooltip with message qwerty. Minor logs were added to each window/button/tooltip windows.
#include <windows.h>
#include <Windowsx.h>
#include <CommCtrl.h>
#include <string>
#include <map>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static HWND hwndTip = 0;
static HWND tool = 0;
WNDPROC old_tooltip_proc = 0;
WNDPROC old_button_proc = 0;
std::string GetLastErrorAsString()
{
//Get the error message, if any.
DWORD errorMessageID = ::GetLastError();
if (errorMessageID == 0)
return std::string(); //No error message has been recorded
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
std::string message(messageBuffer, size);
//Free the buffer.
LocalFree(messageBuffer);
return message;
}
void log_msg(std::string prefix, UINT msg)
{
std::map<UINT, std::string> table
{
{WM_NCHITTEST, "WM_NCHITTEST"},
{TTM_WINDOWFROMPOINT, "TTM_WINDOWFROMPOINT"},
{WM_SETCURSOR, "WM_SETCURSOR"},
{WM_PAINT, "WM_PAINT"},
{WM_NCPAINT, "WM_NCPAINT"},
{WM_ERASEBKGND, "WM_ERASEBKGND"},
{WM_SHOWWINDOW, "WM_SHOWWINDOW"},
{WM_ACTIVATEAPP, "WM_ACTIVATEAPP"},
{WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING"},
{WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED"},
{WM_GETTEXT, "WM_GETTEXT"},
{WM_MOUSELEAVE , "WM_MOUSELEAVE"},
{WM_GETTEXTLENGTH, "WM_GETTEXTLENGTH"},
{WM_NCCALCSIZE, "WM_NCCALCSIZE"},
{WM_TIMER, "WM_TIMER"},
{WM_MOVE, "WM_MOVE"},
{WM_MOUSEMOVE, "WM_MOUSEMOVE"},
{WM_LBUTTONDOWN, "WM_LBUTTONDOWN"},
{TTM_RELAYEVENT, "TTM_RELAYEVENT"},
{SB_SETTEXTA, "SB_SETTEXTA"}
};
if (table.find(msg) == table.end())
{
OutputDebugString((prefix + " " + std::to_string(msg) + "\n").c_str());
return;
}
OutputDebugString((prefix + " " + table.at(msg) + "\n").c_str());
}
LRESULT CALLBACK tooltip_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
log_msg("TOOLTIP", message);
return CallWindowProc(old_tooltip_proc, hwnd, message, wParam, lParam);
}
LRESULT CALLBACK button_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
log_msg("BUTTON", message);
return CallWindowProc(old_button_proc, hwnd, message, wParam, lParam);
}
void createToolTip(HINSTANCE hInstance, HWND parent_window)
{
hwndTip = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
parent_window, NULL, hInstance,
NULL);
old_tooltip_proc = (WNDPROC)SetWindowLongPtr(hwndTip, GWLP_WNDPROC, (LONG_PTR)tooltip_proc);
if (!hwndTip)
{
MessageBox(parent_window, "CreateWindowEx TOOLTIPS_CLASS failed", "ERROR", MB_OK);
return;
}
}
TOOLINFO get_tool_info(HWND tool)
{
TOOLINFO g_toolItem = { 0 };
g_toolItem.cbSize = sizeof(g_toolItem);
g_toolItem.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
g_toolItem.hwnd = GetParent(tool);
g_toolItem.uId = (UINT_PTR)tool;
g_toolItem.hinst = NULL;
g_toolItem.lpszText = LPSTR_TEXTCALLBACK;
return g_toolItem;
}
void register_tool(HWND _tool)
{
std::string f("qwerty");
TOOLINFO toolinfo = get_tool_info(_tool);
toolinfo.lpszText = const_cast<char*>(f.c_str());
if (SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolinfo) == FALSE)
{
MessageBox(toolinfo.hwnd, "TTM_ADDTOOL failed", "ERROR", MB_OK);
return;
}
tool = _tool;
}
void unregister_tool(HWND tool)
{
TOOLINFO toolinfo = get_tool_info(tool);
SendMessage(hwndTip, TTM_DELTOOL, 0, (LPARAM)&toolinfo);
}
HWND createButton(HWND parent_window)
{
auto handle = CreateWindow(TEXT("button"), TEXT("Hellooooooooooooooooooooooooooooo"),
WS_VISIBLE | WS_CHILD,
10, 10, 800, 250,
parent_window, NULL, NULL, NULL);
old_button_proc = (WNDPROC)SetWindowLongPtr(handle, GWLP_WNDPROC, (LONG_PTR)button_proc);
return handle;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
INITCOMMONCONTROLSEX ic;
ic.dwSize = sizeof(INITCOMMONCONTROLSEX);
ic.dwICC = ICC_TAB_CLASSES;
InitCommonControlsEx(&ic);
static TCHAR szAppName[] = TEXT("ToolTipApplication");
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"),
szAppName, MB_ICONERROR);
return 0;
}
hwnd = CreateWindow(szAppName, // window class name
TEXT("The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
HWND button = createButton(hwnd);
createToolTip(hInstance, ::GetDesktopWindow());
register_tool(button);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
log_msg("window", message);
return DefWindowProc(hwnd, message, wParam, lParam);
}
Tooltip works fine, but I want to replace default behaviour. If you hover over button, tooltip will be shown. But when I quickly move cursor at tooltip then tooltip will be disappeared. I want to disable such vanishing. Tooltips from system tray resembly this behaviour. If you hover over tooltip, it will not be disappeared simultaneously. Something like that:
P.S. I tried to redefine handling of TTM_RELAYEVENT message, but it did not give any results.
Add TTF_TRANSPARENT
TTF_TRANSPARENT: Causes the tooltip control to forward mouse event
messages to the parent window. This is limited to mouse events that
occur within the bounds of the tooltip window.
code:
TOOLINFO get_tool_info(HWND tool)
{
TOOLINFO g_toolItem = { 0 };
g_toolItem.cbSize = sizeof(g_toolItem);
g_toolItem.uFlags = TTF_IDISHWND | TTF_SUBCLASS | TTF_TRANSPARENT;
g_toolItem.hwnd = GetParent(tool);
g_toolItem.uId = (UINT_PTR)tool;
g_toolItem.hinst = NULL;
g_toolItem.lpszText = LPSTR_TEXTCALLBACK;
return g_toolItem;
}
I'm trying to do sort in a ListView. Didn't found any complete example how to do it, only a pieces of code.
I've already created ListView, added columns and items, specified my Comp function. However my problem is that lp1 and lp2 are always 0. I've checked documentation and it says : "These are the values that were specified in the lParam member of the items' LVITEM structure when they were inserted into the list." which I do set.
Here is the code :
#include <windows.h>
#include <stdio.h>
#include <commctrl.h>
#pragma comment(lib,"comctl32.lib")
HWND ListView;
HWND hwnd;
LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nCmdShow)
{
MSG messages;
WNDCLASSEX wincl = { 0 };
wincl.lpszClassName = "Testtttt";
wincl.lpfnWndProc = WindowProc;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof(WNDCLASSEX);
wincl.hIcon = 0;
wincl.hIconSm = 0;
wincl.hCursor = LoadCursor(NULL, IDC_ARROW);
wincl.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(0,0,0));// COLOR_BACKGROUND;
wincl.hInstance = GetModuleHandle(NULL);
RegisterClassEx(&wincl);
hwnd = CreateWindowEx(
0,
wincl.lpszClassName,
"Test",
WS_SYSMENU | WS_EX_STATICEDGE | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
1000,
500,
hwnd,
NULL,
GetModuleHandle(NULL),
NULL);
RECT rec;
GetClientRect(hwnd, &rec);
SetWindowPos(ListView, 0, 0, 0, rec.right, rec.bottom - 23, 0);
ShowWindow(hwnd, nCmdShow);
while (GetMessage(&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
}
void AddListViewItem(char item, char *text)
{
static int i;
LVITEM lis;
lis.mask = LVIF_TEXT /*| LVIF_PARAM*/;
lis.pszText = (LPSTR)(text);
lis.iItem = i;
lis.iSubItem = item;
lis.lParam = i;
if (item==1)
i++;
if (item == 0)
ListView_InsertItem(ListView, &lis);
else
SendMessage(ListView, LVM_SETITEM, 0, (LPARAM)&lis);
}
int CALLBACK myCompFunc(LPARAM lp1, LPARAM lp2, LPARAM sortParam)
{
bool isAsc = (sortParam > 0);
int column = abs(sortParam) - 1;
char tmp[128];
sprintf_s(tmp,sizeof tmp, "%d %d %d", lp1, lp2, column);
MessageBox(0, (LPCSTR)tmp, "myCompFunc", MB_OK);
return 0;
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_NOTIFY)
{
LPNMHDR lpnmh = (LPNMHDR)lParam;
if (lpnmh->idFrom == 8553)
if (lpnmh->code == LVN_COLUMNCLICK)
{
NMLISTVIEW* pListView = (NMLISTVIEW*)lParam;
ListView_SortItems(ListView, myCompFunc, pListView->iSubItem);
}
}
else if (message == WM_CREATE)
{
ListView = CreateWindow(WC_LISTVIEW, (LPCSTR)L"", (WS_CHILD | WS_VISIBLE | LVS_REPORT), 0, 0, 900, 500, hwnd, (HMENU)8553, GetModuleHandle(NULL), NULL);
SendMessage(ListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT); // Set style
LVCOLUMN listColumn = { 0 };
listColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
listColumn.pszText = "Column1";
listColumn.cx = 150;
listColumn.fmt = LVCFMT_LEFT;
ListView_InsertColumn(ListView, 0, &listColumn);
listColumn.pszText = "Column2";
listColumn.cx = 150;
listColumn.iSubItem = 1;
ListView_InsertColumn(ListView, 1, &listColumn);
{
AddListViewItem(0, "a");
AddListViewItem(1, "a 1");
AddListViewItem(0, "b");
AddListViewItem(1, "b 1");
AddListViewItem(0, "c");
AddListViewItem(1, "c 1");
}
}
else if (message == WM_DESTROY)
{
PostQuitMessage(0);
}
else
return DefWindowProc(hwnd, message, wParam, lParam);
return DefWindowProc(hwnd, message, wParam, lParam);
return 0;
}
Holla.
I have one question about placing 'destroying function'.
Globals:
HWND g_hInvisible = NULL;
HINSTANCE g_hInstance = NULL;
Code for WinMain:
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevious, LPSTR lpCmdLine,INT nShows)
{
MSG msg = {0};
WNDCLASSEXW wcMain = {0};
wcMain.cbSize = sizeof(WNDCLASSEXW);
wcMain.style = CS_SAVEBITS;
wcMain.lpfnWndProc = MainWindowProc;
wcMain.hInstance = g_hInstance;
wcMain.lpszClassName = L"MAINCLASS";
RegisterClassEx(&wcMain);
HWND hMainWindow = CreateWindowEx(0, L"MAINCLASS", L"Main Class Window", WS_OVERLAPPEDWINDOW, 100, 100, 100, 100, NULL, NULL, g_hInstance, NULL);
InvisibleWindowInit();
InvisibleWindowTerminate(); // <<< PLACE HERE ?
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
InvisibleWindowTerminate(); // <<< OR PLACE HERE ?
return (int) msg.wParam;
}
Code for InvisibleWindowInit:
BOOL InvisibleWindowInit()
{
WNDCLASSEXW wcInvisible = {0};
wcInvisible.cbSize = sizeof(WNDCLASSEXW);
wcInvisible.style = CS_SAVEBITS;
wcInvisible.lpfnWndProc = InvisibleWindowProc;
wcInvisible.hInstance = g_hInstance;
wcInvisible.lpszClassName = L"INVISIBLE";
RegisterClassEx(&wcInvisible);
g_hInvisible = CreateWindowEx(0, L"INVISIBLE", L"INVISIBLE", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, g_hInstance, NULL);
if (g_hInvisible == NULL)
{
dError = GetLastError();
return FALSE;
}
return TRUE;
}
Code for InvisibleWindowTerminate:
VOID InvisibleWindowTerminate()
{
DestroyWindow(hInvisible);
g_hInvisible = NULL;
}
I want to in another piece of code call InvisibleWindowTerminate
So where is better place, before message loop or after ?
Thank you.