winapi: removing decoration - c++

This looks like a duplicate but hear me first. This is more on the debugging side.
I'm trying to remove the borders of my window using the method here.
What are some things that will make these functions not work? Hiding windows using ShowWindow(Handle, SW_HIDE) doesn't work also. I've made my own Window class with many functions so I don't wanna paste my whole code here.
Here's my Initialization function for the window:
HRESULT SampleWindow::InitializeSimple(SampleWindow* win)
{
HRESULT hr;
HWND hWnd;
SampleWindow* sampleWin;
sampleWin = new SampleWindow();
aMWindowProps->Center();
hWnd = CreateWindowEx(
NULL,
aMWindowProps->aWindowClass,
aMWindowProps->aWindowTitle,
WS_OVERLAPPEDWINDOW,
aMWindowProps->aRealLeft,
aMWindowProps->aRealTop,
aMWindowProps->GetRelativePosWidth(),
aMWindowProps->GetRelativePosHeight(),
HWND_DESKTOP,
NULL,
*aMWindowProps->aHInstance,
sampleWin);
aMWindowProps->aHwnd = &hWnd;
hr = hWnd ? S_OK : E_FAIL;
win->aHwnd = &hWnd;
//ShowWindow(hWnd, SW_SHOWNORMAL);
return hr;
}
WindowProps as you can see contains various info about the window being created.
I also have a HWND pointer variable in my class which points to the window handler.
Here are some things I've tried on my main, where sw2 is a pointer to my window class:
ShowWindow(*sw2->aHwnd, SW_SHOW);
//ShowWindow(*sw2->aHwnd, nCmdShow);
LONG lStyle = GetWindowLong(*sw2->aHwnd, GWL_STYLE);
lStyle &= WS_POPUP;
//lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
SetWindowLong(*sw2->aHwnd, GWL_STYLE, lStyle);
//ShowWindow(*sw2->aHwnd, SW_MINIMIZE);
//ShowWindow(*sw2->aHwnd, SW_HIDE);
//ShowWindow(*sw2->aHwnd, SW_HIDE);
//SetWindowLong(*sw2->aHwnd, GWL_STYLE, GetWindowLong(*sw2->aHwnd, GWL_STYLE) && ~ WS_BORDER && ~ WS_SIZEBOX && ~ WS_DLGFRAME);
SetWindowPos(*sw2->aHwnd, HWND_TOP, sw2->aMWindowProps->aRealLeft, sw2->aMWindowProps->aRealTop, sw2->aMWindowProps->aRealWidth, sw2->aMWindowProps->aRealHeight, SWP_FRAMECHANGED);
//LONG lExStyle = GetWindowLong(*sw2->aHwnd, GWL_EXSTYLE);
//lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
//SetWindowLong(*sw2->aHwnd, GWL_EXSTYLE, lExStyle);
//SetWindowPos(*sw2->aHwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
I'd just like some suggestions on where to debug my code. I know the functions work as I've tested it on a much simpler window project (sample project from Microsoft).

As Jonathan Potter already pointed out in his comment, your mistake is:
aMWindowProps->aHwnd = &hWnd;
hr = hWnd ? S_OK : E_FAIL;
win->aHwnd = &hWnd;
where HWND hWnd is only valid in the scope of the current methode. I guess that you defined aHwnd in your class as something like:
HWND *aHwnd;
which is at least unnecessary. You seem to mistake a HANDLE (a HWND is nothing else) as a kind of instance/object itself. It isn't, it is more like a pointer or reference. You can always safely write:
HWND myAttribute=hWnd;
As long as you use it in the same process. (Window handles are even valid across process boundaries, but do not tell anyone about that).
I fact I know no situation where you keep a pointer to a handle instead of the handle itself.
Notice, I explicit wrote about handles, as HWND are a kind of standard window handles.

Related

Win32 Edit printing incorrect characters

I am using a Win32 edit to display debugging information, and I have placed the edit, along with the rest of my basic GUI in a class. But when I output anything to the edit it displays '??????????????????????????'. I think the error lies in my MyGUI::append(LPCSTR) method, although it has always worked perfectly in the past. Any comments/ideas/solutions will be appreciated. If I need to post all the code pertaining to my GUI class please let me know so.
My class lies in the namespace Interface, along with the stand-alone WindowProcedure function, which I call when registering the application with the WNDCLASSEX object.
The win32 edit is not created in the WM_CREATE handle within the WindowProcedure(as it probably should be) as I could not place the function inside my GUI class.
Method that creates the edit:
HWND createEdit( HINSTANCE hInst, HWND hwnd, int appBott, int appTop ){
return CreateWindowEx( WS_EX_APPWINDOW,
TEXT("EDIT"), TEXT(""),
WS_BORDER | WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | ES_MULTILINE| WS_VSCROLL | WS_HSCROLL,
10, 10, appBott-25, appTop-50,
hwnd,
(HMENU) 102,
hInst,
NULL );
}
Used in 'guiCreate()' method as:
HWND hEdit = createEdit( hInst, hWin, appWidth, appHeight );
Method that displays text in edit:
void Interface::MyGUI::append( LPCSTR text ){
if( created && !stopAll ){
int TextLen = SendMessage(hEdit, WM_GETTEXTLENGTH, 0, 0);
SendMessageW(hEdit, EM_SETSEL, (WPARAM)TextLen, (LPARAM)TextLen);
SendMessageW(hEdit, EM_REPLACESEL, FALSE, (LPARAM) text);
}
}
Used in main program as:
MyGUI form(); //initialize form
form.append( (LPCSTR)"Example text\n" );
Input text: 'Example text.\n'
Displayed text: '?????????????? l'
You are targeting ANSI it would seem. In that case, don't call SendMessageW, call SendMessageA or even SendMessage and let that be expanded to SendMessageA.
You call SendMessageW but pass ANSI encoded text. When you called SendMessageW you promised to send UTF-16 encoded text.
However, you should stop targeting ANSI I think. Target Unicode instead. Stop using the TEXT() macro and use the L prefix for your string literals. And stop casting string types. That (LPCSTR) cast is asking for trouble. When you cast like that you tell the compiler that you know better than it does. And usually that is not the case.

Null handle error

I am working on a Win32++ application that has a listview in the main window. This is my code:
HWND CarsListView = NULL;
switch (message)
{
case WM_SHOWWINDOW:
CarsListView = CreateListView(hWnd);
ShowWindow(CarsListView, SW_SHOW);
break;
case WM_SIZING:
{
if(!CarsListView)
MessageBox(hWnd, _T("Null handle."), _T("Error"), MB_ICONERROR | MB_OK);
RECT WindowRect;
GetWindowRect( hWnd, &WindowRect);
SetWindowPos(CarsListView, NULL, 0, 0, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, SWP_SHOWWINDOW);
}
break;
// ...
}
and the CreateListView definition is this:
HWND CreateListView (HWND hwndParent)
{
INITCOMMONCONTROLSEX icex; // Structure for control initialization.
icex.dwICC = ICC_LISTVIEW_CLASSES;
InitCommonControlsEx(&icex);
RECT rcClient; // The parent window's client area.
GetClientRect (hwndParent, &rcClient);
// Create the list-view window in report view with label editing enabled.
HWND hWndListView = CreateWindow(WC_LISTVIEW,
L"",
WS_CHILD | LVS_REPORT | LVS_EDITLABELS,
0, 0,
rcClient.right - rcClient.left,
rcClient.bottom - rcClient.top,
hwndParent,
/*(HMENU)*/NULL,
hInst,
NULL);
return (hWndListView);
}
When the window receives WM_SIZING, I get that CarsListView = NULL
What can I do to have that handle pointing to my listview?
Three way to do that kind of stuff.
The Ugly
Store your CarsListView HWND in a static. You can't have 2 instance of the parent windows.
The Bad
Use SetWindowsLongPtr(parentHWND,GWLP_USERDATA,CarsListViewHWND) in your init and GetWindowLongPtr when needed. It's fast you can have as many instance as you want, but if you need more than one information I recommend storing a struct with your HWND inside instead of single HWND for future extensibility.
The Good ?
Use SetProp(parentHWND,"Your Unique String",hDataHandle); its by far the more code but with that usage you can use it on every windows without caring if the USERDATA is already used or not. It's the best approach when you need to add personal property to a windows/code you can't be sure how it will be used or change over time
There are two ways to do this: The "good" way and the "bad" way.
The "bad" way is to simply declare the local variable as static, however it means you can't create two windows of this type in the same process.
The "good" way is to memorize it in a heap-allocated structure, and store a pointer to this structure in the Window information using SetWindowLongPtr(). You can then retrieve this structure with GetWindowLongPtr().
I would create the listview in WM_CREATE and not in WM_SHOWWINDOW. Also make the handle either global or static.
Or you can also create the list view globally and keep it hidden and just make it visible and set its position whenever you want it to do.

How Create derived from CWnd POP UP Window?

I created class CSurfaceWnd from CWnd by Class Wizard. I tried to create window but getting error.
That's my code of creating:
if(!m_pSurfaceWnd)
{
CString m_NameClass = AfxRegisterWndClass(
CS_VREDRAW | CS_HREDRAW,
::LoadCursor(NULL, IDC_ARROW),
(HBRUSH) ::GetStockObject(WHITE_BRUSH),
::LoadIcon(NULL, IDI_APPLICATION));
m_pSurfaceWnd = new CSurfaceWnd;
CRect rcTemp;
GetWindowRect(rcTemp);
VERIFY(m_pSurfaceWnd->CreateEx(WS_EX_CLIENTEDGE, m_NameClass, NULL, WS_POPUP | WS_VISIBLE, rcTemp, mpWnd, 1));
//DWORD dw =GetLastError();
m_pSurfaceWnd->ShowWindow(SW_SHOW);
}
else
m_pSurfaceWnd->ShowWindow(SW_SHOW);
How can You see I'm creating pop up window that's why I'm using CreateEx. I have registered class and in debug mode I see a number of new class in m_NameClass. But CreateEx returned false.
Please help me. Probably you will see some error that I can't see.Please Don't send me to MSDN I have read it a lot of times.
Thank you
First of all, you have to check whether mpWnd is valid object.
BOOL isValid = ::IsWindow(mpWnd->GetSafeHwnd());
If mpWnd is invalid value, CreateEx function will return 0 because of WS_POPUP style.

Win32 SetForegroundWindow unreliable

I have a rather complex series of applications which depend on the ability to switch applications in the foreground.
My problem is, every 5 or 6 times of switching the applications in the foreground, it simply fails to bring the application forward. GetLastError does not report any issues. Often times I see the correct application flash in the foreground for a moment then the previous application is visible.
I have a Manager application which I have source for, it spawns and controls about 4 applications which I do not have source for. one of the applications it spawns/controls is also a manager which spawns/controls about 5 applications.
This is a sort of kiosk design so the user wont even have a keyboard or mouse, just a touch screen.
I have tried every combination of the Win32 calls to control them I am just out of ideas.
My first attempt was:
SetWindowPos(hApp, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(hApp, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
My second attempt was:
SetForegroundWindow(hApp);
SetActiveWindow(hApp);
SetFocus(hApp);
my third attempt:
DWORD dwThreadID = GetWindowThreadProcessId(hApp, NULL);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), true);
SetForegroundWindow(hApp);
SetActiveWindow(hApp);
SetFocus(hApp);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), false);
my forth attempt:
DWORD dwThreadID = GetWindowThreadProcessId(hApp, NULL);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), true);
SetWindowPos(hApp, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(hApp, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(hApp);
SetActiveWindow(hApp);
SetFocus(hApp);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), false);
I feel like I am missing an important gotcha when it comes to window switching. I know that only the foreground process can switch windows around but as my main Manager program is spawning and starting all the other processes which I need to control, I feel like it should be capable of moving these windows around. Any suggestions or advice is appreciated.
I was having the same issue and I didn't want to mess up with threads. On experimenting I observed a simple hack to make SetForegroundWindow() work in the expected manner. Here is what I did:
Minimize the window if its not already minimized
Restore the minimized window
Call SetForegroundWindow(), and your window will be on top
Your AttachThreadInput() hack is (I think) a known way to defeat the focus stealing counter-measures in Windows. You are using the wrong handle though, you want to attach to the thread that currently has the focus. Which won't be hApp, you wouldn't need this code otherwise.
Use GetForegroundWindow() to get the handle to the window with the focus.
AttachThreadInput(
GetWindowThreadProcessId(GetForegroundWindow(), NULL),
GetCurrentThreadId(), TRUE
);
Although I think the 2nd argument needs to be thread ID of hApp. Because you don't want to shove your own window if I understood correctly. Not sure if that can work.
The easiest solution in C# to bring a window in the foreground:
Once you have the handle for the window, you can simply call:
SetWindowPos(handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
ShowWindow(handle, 5);
SetForegroundWindow(handle);
// If it is minimized, show the window
if (IsIconic(handle))
{
ShowWindow(handle, 3);
}
where
const int SWP_NOMOVE = 0x0002;
const int SWP_NOSIZE = 0x0001;
const int SWP_SHOWWINDOW = 0x0040;
Some windows are locked with setforeground(...),
you need to unlock them. This sequence is useful with any window:
HWND needTopWindow=FindWindow(TEXT("classname"), TEXT("window name"));
the classname and window name you can retrieve with ranorexspy from e.g.
nanoware.cz
if(!::IsWindow(needTopWindow)) return;
BYTE keyState[256] = {0};
//to unlock SetForegroundWindow we need to imitate Alt pressing
if(::GetKeyboardState((LPBYTE)&keyState))
{
if(!(keyState[VK_MENU] & 0x80))
{
::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
}
}
::SetForegroundWindow(needTopWindow);
if(::GetKeyboardState((LPBYTE)&keyState))
{
if(!(keyState[VK_MENU] & 0x80))
{
::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}
}
DWORD dwThreadID = GetWindowThreadProcessId(needTopWindow, NULL);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), true);
SetWindowPos(needTopWindow, HWND_TOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetWindowPos(needTopWindow, HWND_NOTOPMOST, NULL, NULL, NULL, NULL, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(needTopWindow);
SetActiveWindow(needTopWindow);
SetFocus(needTopWindow);
AttachThreadInput( dwThreadID, GetCurrentThreadId(), false);
We had a similar problem a couple of years ago. We could solve it by the following function call:
SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, 0, SPIF_UPDATEINIFILE);
Give it a try. See the documentation here.
Try pushing the other application windows to the background first.
Also its a bit strange that you use SetWindowPos (SWP) to push a window to the foreground then push it out of the forgreound before using SetForegroundWindow to bring it back foward. Personally I've always used the SWP method without any issue ... but I've always pushed the other windows to the bottom as well.
You also need to consider the chances of window being minimized. If the window or various application are minimized then SetForegroundWindow(hApp) won't work. To be safe use ShowWindow(hApp, 9); I prefer value 9. Have a look at its documentation and choose which you find fit for you.

Unicode tooltips not showing up

I am trying to display unicode tooltips in my application window, however they do not seem to display. Non-unicode text shows up correctly but as soon as I try doing unicode no tooltip shows up. The following is what I am currently doing, any help is appreciated thank you.
HWND parentHwnd = pickInfo->getViewer().getCachedHwnd();
CWnd *pWnd = CWnd::FromHandlePermanent(parentHwnd);
HINSTANCE hInstance = GetModuleHandle(NULL);
if (isUnicode)
m_toolInfoW.lpszText = L"This tooltip does not show up at all.";
else
m_toolInfoA.lpszText = "Non unicode text";
if (!m_bTooltipInitialized){
::SendMessage(m_tooltipHwnd, WM_DESTROY, 0,0);
if(isUnicode)
m_tooltipHwnd = CreateWindowExW(WS_EX_TOPMOST,
TOOLTIPS_CLASSW, NULL,
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
parentHwnd, NULL, hInstance, NULL);
else
m_tooltipHwnd = CreateWindowEx(WS_EX_TOPMOST,
TOOLTIPS_CLASS, NULL,
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
parentHwnd, NULL, hInstance, NULL);
if (GetLastError() != 0)
return;
::SetWindowPos(m_tooltipHwnd, HWND_TOPMOST,
0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
// Set the max text width before multi-line tooltip is used.
::SendMessage(m_tooltipHwnd, TTM_SETMAXTIPWIDTH, 0, m_nMaxWinTooltipWidth);
if (isUnicode){
m_toolInfoW.uFlags = TTF_SUBCLASS | TTF_IDISHWND | TTF_TRACK;
m_toolInfoW.hinst = hInstance;
m_toolInfoW.hwnd = parentHwnd;
m_toolInfoW.uId = (UINT_PTR)parentHwnd;
::GetClientRect (parentHwnd, &m_toolInfoW.rect);
::SendMessage(m_tooltipHwnd, TTM_ADDTOOLW, 0, (LPARAM) (LPTOOLINFOW) &m_toolInfoW);
::SendMessage(m_tooltipHwnd, TTM_ACTIVATE, TRUE, (LPARAM)(LPTOOLINFOW) &m_toolInfoW);
}
else{
m_toolInfoA.uFlags = TTF_SUBCLASS | TTF_IDISHWND;
m_toolInfoA.hinst = hInstance;
m_toolInfoA.hwnd = parentHwnd;
m_toolInfoA.uId = (UINT_PTR)parentHwnd;
::GetClientRect (parentHwnd, &m_toolInfoA.rect);
::SendMessage(m_tooltipHwnd, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &m_toolInfoA);
::SendMessage(m_tooltipHwnd, TTM_ACTIVATE, TRUE, (LPARAM)(LPTOOLINFO) &m_toolInfoA);
}
m_bTooltipInitialized = true;
}
if (isUnicode)
::SendMessage(m_tooltipHwnd, TTM_UPDATETIPTEXTW, 0, (LPARAM) (LPTOOLINFOW) &m_toolInfoW);
else
::SendMessage(m_tooltipHwnd, TTM_UPDATETIPTEXT, 0, (LPARAM) (LPTOOLINFO) &m_toolInfoA);
//Repaint the screen so that the area beneath the previous location of the tooltip is restored correctly.
::UpdateWindow(pWnd->GetParentOwner()->GetSafeHwnd());
pWnd = NULL;
The problem is that you try to use common controls version 6, but you does not get to use it.
More in details,
typedef struct tagTOOLINFOW {
UINT cbSize;
UINT uFlags;
HWND hwnd;
UINT_PTR uId;
RECT rect;
HINSTANCE hinst;
LPWSTR lpszText;
LPARAM lParam;
#if (NTDDI_VERSION >= NTDDI_WINXP)
void *lpReserved;
#endif
} TTTOOLINFOW, NEAR *PTOOLINFOW, *LPTTTOOLINFOW;
for xp+, the header file CommCtrl.h assume you'll use comctl version 6, but if you does not enable it explictly with manifest file, you'll still use the old comctl version 5.x. Then here comes the problem, the size of TOOLINFO of version 5.x is different to version 6.x.
So if you need to use comctl version 5 under windows xp+, you should init TOOLINFO with follwing code,
TOOLINFO ti;
ti.cbSize = sizeof(TOOLINFO) - 4;
Otherwise, you should enable visual-style look with manifest file or prgram directive:
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
Finally, I'd recommand you always enable visual-look in xp+. Here are the comparision of visual effects:
Note: If you use ANSI/MBCS to compile the program, the sizeof(TOOLINFO) will be 48, which have already remove the lpReserved member. So ANSI version would works, but UNICODE would fail.
Good explanation and a solution that will work by Jichao above, but hard-wiring the size of the TOOLINFO structure will fix only the tooltips. If the problem is that the program was compiled with common controls 6.0+ in mind, but may be run on (say) a Windows XP system with 6.0+ either not installed, or not fully installed (like someone installed IE, but never used or updated it), then the more general solution is to restrict the application to using only 5.x common controls.
As can be seen here, there are more things that have structure size changes than just tooltips.
What I did to insure that everything would work on Windows XP is put the following at the very top of my program, before any includes (in the case of visual studio, a good place would be at the top of targetver.h if you have one):
#define _WIN32_WINNT 0x0500
In the Unicode case you have TTF_TRACK, which I believe requires you to manually show or hide the tooltip. In the ANSI case, you don't have that option.
http://msdn.microsoft.com/en-us/library/bb760252(VS.85).aspx
Scroll down to "Implementing Tracking Tooltips".