Adding Windows Form to a DirectX application? - windows

I'm working on a directx application and was wondering how I could add a regular window to the application, one which has text boxes, command buttons and all.

For a window to exist it will require a windows forms message pump :
A Win32 message pump typically looks something this and was the heart of win32 programming.
MSG msg;
while(GetMessage(&msg, hwnd, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
// do stuff
}
Today, the C# language tends to abstract the message pump away but you can still get to it.
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// do stuff
}
You need a call to application.run to launch a windows forms with active message pump. see :
http://msdn.microsoft.com/en-us/library/ms157900.aspx
Hey Ed: This is something you might be looking for :
http://www.directxtutorial.com/Tutorial9/A-Win32/dx9A3.aspx . It talks about creating a window from directx

As far as I know you would have to create a parent window to hold both the "window" that DirectX image is rendered to and the regular window with controls.

Related

Owner-drawn CTabCtrl in WTL

WTL/WIN32 newbie here, struggling to understand how messages are passed around.
I'm trying to write an owner-drawn CTabCtrl in WTL. For some (at least to me) incomprehensible reason, WM_DRAWITEM is sent to the parent window, not to the window that actually needs to know. Which makes it difficult to make a nice, self-contained GUI class to simply replace CTabCtrl. I could always capture the message in the parent and pass it on to the tab control, but that would be poor OO design. Is there a way to intercept the message, without requiring extra re-routing code in the owner/parent class?
EDIT: After a bit of googling, I now have
class CQueryTabCtrl :
public CWindowImpl<CQueryTabCtrl, CTabCtrl>,
public COwnerDraw<CQueryTabCtrl>
{
public:
DECLARE_WND_SUPERCLASS(NULL, CTabCtrl::GetWndClassName())
BEGIN_MSG_MAP(CQueryTabCtrl)
CHAIN_MSG_MAP(COwnerDraw<CQueryTabCtrl>)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
BOOL PreTranslateMessage(MSG* pMsg)
{
pMsg;
return FALSE;
}
void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/)
{
}
void DrawItem ( LPDRAWITEMSTRUCT lpdis )
{
CDCHandle dc = lpdis->hDC;
CDC dcMem;
dcMem.CreateCompatibleDC ( dc );
dc.SaveDC();
dcMem.SaveDC();
dc.FillSolidRect ( &lpdis->rcItem, RGB(255,0,0) );
dcMem.RestoreDC(-1);
dc.RestoreDC(-1);
}
};
Which is obviously utterly wrong, since DrawItem() is never called.
WM_DRAWITEM is sent to parent by design.
Sent to the parent window of an owner-drawn button, combo box, list box, or menu when a visual aspect of the button, combo box, list box, or menu has changed.
You handle it on hosting window, and with WTL you might leverage COwnerDraw class on it and/or reflect messages there so that they are sent back to the window where your subclassing WindowProc would handle them as you perhaps originally planned.
This answer is a bit late to the party, but might help others...
There's no way to directly achieve reflected messages w/o extra routing code, because that's how Window's window messaging works, as Roman points out.
ATL however has mechanisms to reflect messages onto child windows, which at least helps in keeping self-written code to a minimum.
1) Opt-In to reflection
This requires an extra step in your parent window, in order to tell it to reflect messages from child windows onto them, using the REFLECT_NOTIFICATIONS() macro:
// Just a made-up dialog class for outlining message reflection installed on the parent window
class SomeDialog : public CDialogImpl<SomeDialog, CWindow>
{
public:
BEGIN_MSG_MAP_EX(SomeDialog)
REFLECT_NOTIFICATIONS()
END_MSG_MAP()
};
2) Handle reflected (owner-draw) messages
Because your control will receive reflected messages, and the COwnerDraw mixin provides an alternative message map for those, you simply chain to that message map, using the CHAIN_MSG_MAP_ALT() macro.
class CQueryTabCtrl :
public CWindowImpl<CQueryTabCtrl, CTabCtrl>,
public COwnerDraw<CQueryTabCtrl>
{
public:
DECLARE_WND_SUPERCLASS(NULL, CTabCtrl::GetWndClassName())
BEGIN_MSG_MAP(CQueryTabCtrl)
CHAIN_MSG_MAP_ALT(COwnerDraw<CQueryTabCtrl>, 1)
END_MSG_MAP()
void DrawItem(LPDRAWITEMSTRUCT)
{
// ...
}
};
Also see a complete owner-drawn tablist control from the wtlext repository, which can serve as an example (Dislaimer: I am associated with the author FireDaemon Technologies Ltd).

Starting a windows-application with focus

I'm writing a small Windows application in Visual C++ without MVC. Its really small, it just contains one textfield, an OK-Button and an Cancel-Button.
The application is started by a background-process when user starts printing. When opening the application doesn't get focus, isn't even visible.
For the user it's importend that the application is directly in focus, so they have as lease clicks as possible to use it.
I tried many many things to get the application in focus:
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
SetForegroundWindow(hWnd);
ShowWindow(hWnd, SW_RESTORE);
SetFocus(hWnd);
I even repeated this calls in a timer. All of this doesn't work. Now I found some remarks on MSDN:
The system restricts which processes can set the foreground window. A
process can set the foreground window only if one of the following
conditions is true:
The process is the foreground process.
The process was started by the foreground process.
The process received the last input event.
There is no foreground process.
The foreground process is being debugged.
The foreground is not locked (see LockSetForegroundWindow).
The foreground lock time-out has expired (see SPI_GETFOREGROUNDLOCKTIMEOUT in SystemParametersInfo).
No menus are active.
Anybody knows a workaround for this?
There is no workaround for this. The whole point of this new Windows behavior is to prevent applications from bringing themselves to the foreground on their own and being a nuisance. In your case, I would suggest using a notification icon and showing a balloon message when necessary instead of a window. However, even in this case your notification icon can be hidden by the user and there is no workaround, for the same reason as above.
Now, this is coming from a Java developer and not a Visual C++ developer, but can you maybe set the frame/window/whatever-its-called-in-visual-c to be always on top? In Java, if you have a JFrame, say myJFrame, you can call myJFrame.setAlwaysOnTop(true) and it stays on top of all other windows. This seems to be a simple workaround to your problem, however it may not be desirable for the user if it's blocking something of theirs on screen.
http://www.thescarms.com/vbasic/alttab.aspx seems to do the job
void forceToFront(HWND hWnd) {
HWND foregroundWindow = GetForegroundWindow();
if (foregroundWindow == hWnd) {
// Window is already Foreground-window
return;
}
if (SetForegroundWindow(hWnd)) {
// could set window to foreground without any tricks
return;
}
// attach thread of foreground-window to this window
DWORD foregroundThread = GetWindowThreadProcessId(foregroundWindow, NULL);
DWORD myThread = GetWindowThreadProcessId(hWnd, NULL);
AttachThreadInput(foregroundThread, myThread, true);
SetForegroundWindow(hWnd);
AttachThreadInput(foregroundThread, myThread, false);
}

Problem with switching application and focus

Sorry but my english is very bad.
I am writing a winapi program in c and I have a problem. The program has a main window and NO DIALOG child windows (controls). The controls are directly attached to the main window. When I switch the application to another application and back again, the focus is set to the main window and not to the control that owns the focus before switching.
My message loop is:
while ((rGetMessage = GetMessage(&msg, NULL, 0, 0)) != 0 && rGetMessage != -1)
{
if(!IsDialogMessage(hwnd_principal, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
What is my error?
I use the IsDialogMessage function for that various keys work on (like TAB key in the controls).
When you switch back to your application, Windows will by default set the keyboard focus to its main window, regardless of which window had the focus when it was deactivated. If you want to do something different you need to handle WM_ACTIVATE and use SetFocus() to restore the focus to the control.

Hiding a control in Windows

I can't figure out how to hide a child window (a control), more specifically a GroupBox and a PushButton. I thought ShowWindow() with SW_HIDE as the second parameter would do the job, but it simply doesn't work. Yet SW_SHOW works just fine. I have the correct window handle for both controls, so that's not the issue.
I googled and all I could find was people asking how to hide dialogs, not controls. Either that or MFC-based applications, which doesn't apply here.
I'm using pure Windows API, no MFC.
What am I getting wrong?
EDIT: More info: I'm writing some simple class wrappers for WinApi controls. The WindowsControl class has, along other methods, the following methods for showing and hiding the Control:
void Show() {
ShowWindow(this->_hWnd,SW_SHOWNOACTIVATE);
}
void Hide() {
ShowWindow(this->_hWnd,SW_HIDE);
}
Every control inherits from WindowsControl.
This image has the window layout so you understand exactly what I'm doing: http://i.stack.imgur.com/PHQnH.png
When the user clicks inside the "Chipset" Static control, it'll load information for a given Tile (which is stored in an array, but that's irrelevant). Depending on the setting, it'll hide the "Edit bitwall" button on the left and show the empty GroupBox behind it or viceversa.
Just to be clear this isn't something wrong with my windows api wrappers, I am getting the correct HWND. Though ShowWindow might not be able to be called from a Window Procedure that isn't the parent's (that'd be weird).
EDIT2: Using C++ with Visual Studio 2008, no MFC, no WTL, no CLR, no .NET
EDIT3: I'll post even more code so it's easier
Inside the static's window procedure, I handle WN_LBUTTONDOWN like this:
case WM_LBUTTONDOWN: {
...
update_tiledata(c, l)
void update_tiledata(GroupBox * c, ListView* l ) {
...
if (chp_copy.Tiles[selectedTile].Pass() == PT_BITWALL) {
c->Controls(CTL_BTNEDITBIT)->Show();
c->Controls(CTL_FRPHOLD)->Hide();
} else {
c->Controls(CTL_FRPHOLD)->Show();
c->Controls(CTL_BTNEDITBIT)->Hide();
}
update_edits();
}
The ommited code does nothing to affect the classes, as I said before, ShowWindow with SW_HIDE IS getting called, with the correct HWND, but nothing is happening.
A control in a Window or dialog can be hidden using
ShowWindow(hControlWin, SW_HIDE);
In a dialog you can retrive the controls window handle by calling
GetDlgItem(hDlg, < CtrlID >);
Typically you write something like:
ShowWindow(GetDlgItem(hDlg, 2), SW_HIDE);
It would be helpful if you give more information and some code: How did you create the controls? What language, compile and framework did you use?
I think the function call you want is EnableWindow I have used this before to disable a button on a form. You will need to get an handle to the Window (object) first though so you might want to use EnumChildWindows to iterate through all the controls to find the one you want.

How can I stop window rendering and later resume?

I'd like to prevent my window from being updated until I finish receiving data from the server and render it. Can I hook on the WM_PAINT event, or better still call some Win32API method to prevent the window from being updated and unfreeze it later?
More info:
In the context of an MMC snapin written in C#, our application suffers from annoying flickering and double sorting behaviour:
We use MMC's listViews, but since we subscribe to the sort event.
MMC does it's own magic and sorts the page being displayed (and we can't override that), and when we receive a reply from our server we change the listView again.
each row change is done sequentially, there's no beginUpdate etc. (AFAIK).
Normally hooking into WM_PAINT is the way to go, but make sure you also ignore all WM_ERASEBKGND notifcations, otherwise you'll still get flicker, because Windows erases the Windows area for you. (Return non-zero to prevent Windows from doing that)
One other possibility is to use the LockWindowUpdate function, but it has some drawbacks:
Only one window can be locked
Upon unlock the whole desktop and all sub-windows (i.e. everything) is repainted, resulting in short flash of the whole desktop. (It's worse on XP than on Vista)
Some controls have BeginUpdate and EndUpdate APIs for this purpose.
If you do something (e.g. hook and ignore paint events) do disable painting, then a way to force a repaint later is to call the Invalidate method.
OK, after all searching and checking I've found that LockUpdateWindow is bad idea - see for example articles of Raimond Chen OldNewThing. But even to implement the idea of SetRedrawWindow wasn't so simple - because what I had was only received from IConsole2* pConsole->GetMainWindow() HWND handler of main window. By setting it to SetRedraw = FALSE it was disappeared in very strange manner. Though to make the procedure run only for the TreeView and not for the whole application (ours left panel) I ran
EnumChildWindows(hWnd, SetChildRedraw, FALSE); //stopping redraw
//... here you do your operations
EnumChildWindows(hWnd, SetChildRedraw, TRUE); //restarting redraw
where SetChildRedraw callback was defined in next way:
#define DECLARE_STRING(str) TCHAR str[MAX_PATH]; ZeroMemory(str, sizeof(str));
BOOL CALLBACK SetChildRedraw(HWND hwndChild, LPARAM lParam)
{
RECT rcChildRect; ZeroMemory(&rcChildRect, sizeof(rcChildRect));
DECLARE_STRING(sText)
GetClassName(hwndChild, sText, MAX_PATH);
if (wcsstr(sText, L"SysTreeView32") != NULL)
{
SetWindowRedraw(hwndChild, lParam);
if (lParam == TRUE)
{
GetWindowRect(hwndChild, &rcChildRect);
InvalidateRect(hwndChild, &rcChildRect, TRUE);
}
}
return TRUE;
}

Resources