According to MSDN
The DeleteObject function deletes a logical pen, brush, font, bitmap,
region, or palette, freeing all system resources associated with the
object. After the object is deleted, the specified handle is no longer
valid.
So one(myself) would think that once DeleteObject is executed, the HANDLE is no longer valid. but what happens to the objects retrieved by ::GetObject() once i delete the object before saving them with other WinAPI calls?
HFONT hFont = reinterpret_cast<HFONT>(::SendMessage(hwndCtrl, WM_GETFONT, 0, 0));
if (nullptr == hFont)
{
LOG_ERROR(L"Invalid font specified");
return false;
}
LOGFONT font = { 0 };
if (0 == ::GetObject(hFont, sizeof(font), &font))
{
LOG_ERROR(L"Failed getting font");
return false;
}
font.lfHeight = nSize;
::DeleteObject(hFont);
HFONT hFontEx = ::CreateFontIndirect(&font);
LPARAM lparam = MAKELPARAM(TRUE, 0);
WPARAM wparam = (WPARAM)(hFontEx);
SendMessage(hwndCtrl, WM_SETFONT, wparam, lparam);
As in the following example, if i decide to delete my HFONT, before sending the new message via SendMessage, i'd retrieve some unexpected results, where other controls gets their font changed, as if i'd generated some kind of a handle leak.
So one(myself) would think that once DeleteObject is executed, the
HANDLE is no longer valid. but what happens to the objects retrieved
by ::GetObject() once i delete the object before saving them with
other WinAPI calls?
With GetObject you get a description for the object, not a new object. It remains the same after handle deletion.
As in the following example, if i decide to delete my HFONT, before
sending the new message via SendMessage, i'd retrieve some unexpected
results, where other controls gets their font changed, as if i'd
generated some kind of a handle leak.
If you want to send a message with deleted HFONT, I guess the result will be the same if you send it with any other garbage.
Related
RELEVANT INFORMATION:
I have a subclass procedure that needs to validate the content of the clipboard before it gets pasted.
I have managed to get the content of the clipboard successfully, at least I think so.
QUESTION:
I do not know how to construct the following if statement ( the following is pseudo code ):
if( clipboard content is OK )
defaul handler;
else
discard message;
MY EFFORTS TO SOLVE THIS:
So far this is what I have in mind:
LRESULT CALLBACK Decimalni( HWND hwnd,
UINT message, WPARAM wParam, LPARAM lParam,
UINT_PTR uIdSubclass, DWORD_PTR dwRefData )
{
switch (message)
{
case WM_PASTE:
{
bool IsTextValid = true; // indicates validity of text
if( OpenClipboard(hwnd) ) // open clipboard
{
HANDLE hClipboardData;
// get clipboard data
if( hClipboardData = GetClipboardData(CF_UNICODETEXT) )
{
// Call GlobalLock so that to retrieve a pointer
// to the data associated with the handle returned
// from GetClipboardData.
wchar_t *pchData = (wchar_t*)GlobalLock(hClipboardData);
// copy clipboard data so we can free clipboard
wchar_t result[10]; // I just need first 9 characters
memset( result, L'0', sizeof(result) );
// copy clipboard data WITH TRUNCATION!!!
wcsncpy_s( result, 10, pchData, _TRUNCATE );
// Unlock the global memory.
GlobalUnlock(hClipboardData);
/*** parse the text for validity ****/
// code for parsing text
// update IsTextValid to indicate success or fail
/*** end of parsing *******/
}
// Finally, when finished I simply close the Clipboard
// which has the effect of unlocking it so that other
// applications can examine or modify its contents.
CloseClipboard();
}
// here should be the problematic if statement
if( IsTextValid )
return ::DefSubclassProc( hwnd, message, wParam, lParam);
else
return FALSE;
}
break;
case WM_CHAR:
{
// filter out some invalid keys
}
break;
case WM_NCDESTROY:
::RemoveWindowSubclass( hwnd, Decimalni, 0 ); // remove subclassing
break;
}
return ::DefSubclassProc( hwnd, message, wParam, lParam);
}
Is my idea correct or is there another way to form my if statement?
Thank you.
Best regards.
The code seems plausible, down to the action taken. Bit clunky, but that's Windows API. There may be better ways, but this should work.
One mistake: if the text is OK, you should call DefSubclassProc, not the default window procedure.
If the text is not OK you could consider emptying the clipboard. There is not enough here about your other requirements to talk about that.
I recently started coding in C++ and I am very new to it. (I code in Javascript, PHP, Java and Obj-C more often)
I'm practicing how to hook a message box and change its position. This is what I have in my .cpp file (after reading this SO post).
#include <iostream>
#pragma comment(lib,"User32.lib")
#include <windows.h>
HHOOK hhookCBTProc = 0;
LRESULT CALLBACK pfnCBTMsgBoxHook(int nCode, WPARAM wParam, LPARAM lParam){
if (nCode == HCBT_CREATEWND)
{
CREATESTRUCT *pcs = ((CBT_CREATEWND *)lParam)->lpcs;
if ((pcs->style & WS_DLGFRAME) || (pcs->style & WS_POPUP))
{
HWND hwnd = (HWND)wParam;
SetWindowPos(hwnd, HWND_TOP,130,122, 0, 0,SWP_NOSIZE);
}
}
return (CallNextHookEx(hhookCBTProc, nCode, wParam, lParam));
}
int main(void)
{
hhookCBTProc = SetWindowsHookEx(WH_CBT,pfnCBTMsgBoxHook,
0, GetCurrentThreadId());
int sResult = MessageBox ( NULL, "Hooked!", "oh my", MB_OK );
UnhookWindowsHookEx(hhookCBTProc);
return 0;
}
For some reason the position of the message box isn't changing. Where did it go wrong?
(I know I can create a customized window or dialog. But I am doing it this way because I want to learn how to hook a message box and where I did wrong.)
Firstly you should check in the debugger that your hook is actually being called, if you haven't already.
Secondly, at the time the HCBT_CREATEWND hook event is triggered, the window has only just been created - the system has yet to size and position it. It will do this with the values in the CREATESTRUCT after the hook returns - overriding your SetWindowPos call.
See the docs from MSDN on the lParam value for this particular hook event:
Specifies a long pointer to a CBT_CREATEWND structure containing
initialization parameters for the window. The parameters include the
coordinates and dimensions of the window. By changing these
parameters, a CBTProc hook procedure can set the initial size and
position of the window.
Therefore, the correct way to use this hook to change a window's position is to modify the values in the CREATESTRUCT directly.
Also note that it's quite possible that the dialog manager sizes and positions the window after creation, so if you find that this still isn't working for you, you may need to try watching for the HCBT_MOVESIZE event instead.
From the docs
At the time of the HCBT_CREATEWND notification, the window has been
created, but its final size and position may not have been determined
and its parent window may not have been established.
Maybe try hooking into CBT_ACTIVATE instead.
whenever I execute the below code, my memory in task manager for the application keeps on increasing endlessly. I found similiar questions here on stackoverflow and I did some DeleteObject calls like they stated but this still did not solve the ever increasing memory when this code executes.
How can this be solved? What am I doing wrong?
SetControlPicture(const UINT ID_PICTURE_CONTROL)
{
CImage image;
CBitmap bitmap;
HRESULT hresult;
CStatic* pItem = (CStatic*)GetDlgItem(ID_PICTURE_CONTROL);
hresult = image.Load(_T("./Data/Images/RED_ON.png"));
if(hresult != E_FAIL)
{
HBITMAP hBitMap = image.Detach();
bitmap.Attach(hBitMap);
HBITMAP hBitMapPrev = pItem->SetBitmap(bitmap);
if (hBitMapPrev)
{
DeleteObject(hBitMapPrev); // *** do not forget to delete the previously associated bitmap
}
DeleteObject(hBitMap);
}
}
AFAIK According to the documentation this must leak. Since Common Control ver. 6.0 you are repsonsible to delete the Bitmap. It is not enough to delete the Bitmap that was returned.
http://msdn.microsoft.com/en-us/library/windows/desktop/bb760782(v=vs.85).aspx
In version 6 of the Microsoft Win32 controls, a bitmap passed to a static control using the STM_SETIMAGE message was the same bitmap returned by a subsequent STM_SETIMAGE message. The client is responsible to delete any bitmap sent to a static control.
I'm new to the WTL C++. I'm really confused about the parameters that go into the RedrawWindows function especially for the flags. I'm just trying to update a window everytime I draw a line, but I don't exactly understand how
LRESULT CDrawView::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
int xPos= GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
end.X = xPos;
end.Y = yPos;
Pen pen(Color(0, 0, 255));
m_GraphicsImage.DrawLine(&pen, start.X, start.Y, end.X, end.Y);
I try to call RedrawWindow here,
RedrawWIndow(NULL,NULL, NULL, RDW_INTERNALPAINT)
So everytime I release the left mouse button the window gets updated. I'm having a really hard time understanding the parameters that go into the Redraw Function. I tried putting them all null minus the last one but Visual studio says that the function doesn't take 4 parameters even though I read the msdn microsoft...
You are not calling the global RedrawWindow.
You're calling the member function CWindow::RedrawWindow, which takes 3 parameters.
BOOL RedrawWindow(
LPCRECT lpRectUpdate = NULL,
HRGN hRgnUpdate = NULL,
UINT flags = RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE
); throw()
Edit:
These three parameters all have default arguments, meaning they don't need to be supplied an RedrawWindow() alone should work.
This is not the way you should use and you are supposed to be using the API. Your mouse button handler should call Invalidate() or InvalidateRect with specific part of the window you are marking as needing an update. Your window will then receive WM_PAINT event at the first OS convenience and your paint handler would paint the line.
RedrawWindow might work out this time, however is likely to be a base of a next problem very soon because you are already on the wrong way.
I want to get handle of child window, but cannot.
I want to automatically insert text in an Edit control.
Here is what I have:
//global var
int id=0;
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
id = GetDlgCtrlID(hwnd);
HWND hwnd_Child;
hwnd_Child = GetDlgItem(hwnd, id);
SendMessage(hwnd_Child, WM_SETTEXT, NULL, (LPARAM)"mYtexttttt");
/* other code */
// id is always 0, why ?
// return FALSE; // stop enumerating
return TRUE; // continue enumeration
}
void MyFunction ()
{
HWND hwnd_Parent;
hwnd_Parent = FindWindow(NULL,"MyTitle"); if(! hwnd)return;
EnumChildWindows(hWnd ,(WNDENUMPROC)EnumWindowsProc, NULL);
}
In WinSpy++, the control IDs of all the components are 000000000. Is it possible that the control ID isn't defined?
How do I find the child handle of some specific (edit box) component if I have the handle of the main window, and the control ID is not defined?
Also, main window is a game application which runs with DirectX, I think.
I want to automatically insert text in a Edit control.
If WinSpy tells you that the control IDs are 0 then getting a 0 back from GetDlgCtrlID() is of course the expected outcome. You'll have to do something else, like counting down the number of EnumWindowsProc() calls and/or calling GetClassName() so you can see it is an edit control. Or GetWindowRect() to go by position.
In your callback method, please do the following:
// get the window text
GetWindowText(hWnd, (LPTSTR)windowText, MAX_PATH);
// get the window info
WINDOWINFO objWinInfo;
GetWindowInfo(hWnd, &objWinInfo)
The above should help you get the child windows.
Also you can do FindWindowEx to the get the child windows.
Control ids are one convenient way to identify child windows; but not the only way. So it is quite possible that control id will be set to arbitrary (or zero) values (in which case the parent window just refers to them directly by their handles.
From your point of view if no control ids exist you must reference them by the position in the tab sequence which should be constant and can be iterated through.