Sign in to follow this  
wijnand

Stuck with WIN32 API

Recommended Posts

Hello everyone, My teacher as an assigment gave me a task to write a Window Manager that could open multiple windows. Each Window can render a scene in either D3D or OpenGL. The problem is I am unable to get my WIN32 API calls to work well, the Windows I am trying to make from Window_Manager do not get build, because I think I made a mistake somewhere thats making the HWND not working well. I posted the code on my Developer journal, and have now rewritten a few things and still It did not work :( http://www.gamedev.net/community/forums/mod/journal/journal.asp?jn=401209 Has anyone else ever had to do something like this, and does anyone know what I am doing wrong? :) Thjank you! Wijnand

Share this post


Link to post
Share on other sites
I've been poring over your code in your journal for a while now, and I couldn't see anything wrong with it. As an experiment I wrote this (THIS IS VERY BAD CODE PURELY TO ILLUSTRATE THAT WIJNAND'S PRINCIPLE SEEMS SOUND)


#include <windows.h>
#include <windowsx.h>

#include <list>

class Window
{
public:
Window(HINSTANCE HIn);

HWND Hw;
};

Window::Window(HINSTANCE HIn)
{
Hw=CreateWindowEx(WS_EX_TOPMOST,"MyWin","",WS_OVERLAPPEDWINDOW,
0,0,640,480,
GetDesktopWindow(),NULL,HIn,NULL);

if(Hw==NULL) return;

ShowWindow(Hw,SW_SHOWDEFAULT); UpdateWindow(Hw); SetFocus(Hw);
}

class WindowManager
{
private:
std::list<Window*> Ws;

public:
WindowManager(){ }

void Add(HINSTANCE HIn);
};

void WindowManager::Add(HINSTANCE HIn)
{
Ws.push_back(new Window(HIn));
}

WindowManager Wm;

LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
int Register(HINSTANCE HIn);

int WINAPI WinMain(HINSTANCE HIn,HINSTANCE,LPSTR CmdLine,int Show)
{
MSG Msg;

if(!Register(HIn)) return 0;

Wm.Add(HIn);
Wm.Add(HIn);

PeekMessage(&Msg,NULL,0,0,PM_NOREMOVE);
while(Msg.message!=WM_QUIT)
{
if(PeekMessage(&Msg,NULL,0,0,PM_REMOVE))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}

return static_cast<int>(Msg.wParam);
}

void OnDestroy(HWND Hw)
{
PostQuitMessage(0);
}

LRESULT CALLBACK WndProc(HWND Hw,UINT Msg,WPARAM wParam,LPARAM lParam)
{
switch(Msg)
{
HANDLE_MSG(Hw,WM_DESTROY,OnDestroy);

default: return DefWindowProc(Hw,Msg,wParam,lParam);
}
}

int Register(HINSTANCE HIn)
{
WNDCLASSEX Wc;

Wc.cbSize=sizeof(WNDCLASSEX);
Wc.style=0;
Wc.lpfnWndProc=WndProc;
Wc.cbClsExtra=0;
Wc.cbWndExtra=0;
Wc.hInstance=HIn;
Wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
Wc.hCursor=LoadCursor(NULL,IDC_ARROW);
Wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
Wc.lpszMenuName=NULL;
Wc.lpszClassName="MyWin";
Wc.hIconSm=LoadIcon(NULL,IDI_APPLICATION);

return RegisterClassEx(&Wc);
}




That creates two windows without a problem, so the principle is obviously sound. I'm stumped as to why yours doesn't work.

Obviously there are many other potential problems with a design like this. All your windows will share the same WndProc with no way of differentiating between them, but I've already pointed you at Oluseyi's article on this subject so I assume that is not an issue you are concerned about at the moment.

Sorry I can't be of more help but I just wanted to give you some code that did work in (sort of) the way your seems to be trying to in the hopes you might spot a difference that could be causing yours to fail. I can't see it.

Share this post


Link to post
Share on other sites
Could you add me on MSN or ICQ? my msn is wijnand@dalmijn.com maybe we can go through it together :) Thank you for all the attempts you have done so far its really appreciated ^^

Share this post


Link to post
Share on other sites
I don't actually have an IM account of any kind. You're of course quite welcome to PM me here, but I'd suggest that if we discuss things in the forums, others far more knowledgable than me (i.e. most GD posters) can also wade in and give you a far better quality of assistance.

Do you have anywhere you could put your entire code up on the internet so people can download and play around with it?

Share this post


Link to post
Share on other sites
Not sure why Palidine edited his/her post but they may well have cracked it.

In the code in your journal, you don't have a message loop in your WinMain, so your windows get created then the program just terminates immediatley.

Was this ommitted from the journal post for brevity, or have you not implemented the message loop in WinMain?

Share this post


Link to post
Share on other sites
that is the strange thing about all of this, even with all break points all over the thing. It still does not crash, it does not give an error (exists with code 0x0).

The problem is that Hwnd is not being properly defined apparantly, whenever I put it throught the debugger it always complains that the HWND is invalidly specified and I think thats the main reason its not opening the window. but I am a bit baffeled its giving me these errors :/

Share this post


Link to post
Share on other sites
Just for clarity, could you post your actual message loop code that sits in WinMain after you create the windows?

[EDIT - although I did just put a breakpoint before the message loop in my mini-app above and the window did appear. Was a bitch to close again though]

Share this post


Link to post
Share on other sites
http://members.gamedev.net/wijnand/programs/Vyper0.1.zip VS2005

Here is the source code of the project.

The Loop is in the Window_Manager.cpp its the LRESULT CALLBACK

I did not make the original messageloop (it was there) but I removed it after trying to figure out what was causing the errors, I didn't think the message loop itself was causing the problems :( I just had to fish a backup out becuase I completly wrecked the code I posted on my journal LOL I even went as far as to just move everything WINAPI related to Window.CPP and it still would not show itself on my screen.

And im probably shooting myself in the foot when the problem is found because it was so stupid lol

Share this post


Link to post
Share on other sites
Add the following two lines to the WNDCLASSEX initialiser:


WNDCLASSEX wc;

>>> wc.cbSize=sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = TEXT("Vyper");
>>> wc.hIconSm=NULL;


Windows now appear.

It was the RegisterClassEx that was failing (it was returning zero). The changes above make it succeed then the remaining code works okay.

There are still major issues with the overall design though.

Share this post


Link to post
Share on other sites
Quote:
Original post by wijnand
I just added those, didn't seem to have any effect. Where did you put your break points at? :)


Sorry - forgot to say you also have your strings muddled in your CreateWindow call. Swap TEXT("Vyper") and TEXT("test") around. The first param is the class and the second param is the caption.

Should be:


this->hWnd = CreateWindow(TEXT("Vyper"), TEXT("test"), WS_OVERLAPPEDWINDOW, x, y, width, height, NULL, NULL, wc.hInstance, NULL);

Share this post


Link to post
Share on other sites
ok will fix that :)

What overall design issues are you Noticing that I should look at? I just tested the code and its working!

The principal idea is now that I am making a general message loop where everything goes to basically the Window Manager should do this I assume? But I am really glad this is finally starting to slowly come together to a workable solution: )

I noticed the link you posted about making a wrapper class was just a bit confused on what the writer was writing honestly :/ It might be me, but it was looping a bit too complicated on what he was doing and why :)

Thanks a lot for all your help though! ^^

Share this post


Link to post
Share on other sites
ah,

Well the idea is basically you boot up a console, and that console is the Kernel.dll when you tell it to open a window it will open one and basically I would assume you would have to make the message queue decentralized? It seems making it centralized kills everything at once, and makes painting something in it impossible :)

Atleast I got the idea working, but I think your article might solve the problem ,but I think it would mean I need to rewrite a few bits of code though :)

Share this post


Link to post
Share on other sites
Quote:
Original post by wijnand
but I think your article might solve the problem ,but I think it would mean I need to rewrite a few bits of code though :)


I would just stress that it is not my article.

When a load of windows share a WndProc, you need to have some way of discerning which particular window the WndProc is being called for. The article shows one very extensible way of doing this, but I am sure there are other methods.

The major problem is that the WndProc has to be a static function and cannot be a class member, otherwise this stuff would be very easy.

Glad to hear it's working, anyway, and good luck with the next stage.

Share this post


Link to post
Share on other sites
I am probably looking at this the complete wrong way. I have just basically decided to rewrite my code in the hopes of making things a big more organized. I decided that I could do the following:

Window Manager basically will just manage what windows is open, when the kernel.cpp closes it will send a WM_DESTROY to all the parent windows so they also get closed. in the Window.cpp I will basically have a entire WINAPI MAIN function with its own message loop running and before the user can make a new screen he has to give a new name of the instance first so that they are unique.

Basically my idea is that you start the new Window like this:

Window::Window(String name, int Type (1 for DX, 2 for OGL) In the Consutrctor of the Window it basicallyt makes a new WNDCLASSEX and adds that name to it, and then it goes in its own WINAPI MAIN loop.

This means that each program does not know of the others existance, the problem is, is this feasable ? because I would prefer that the Rendering engine I will write next can basically communicate with the individual windows and basically ensure that it does not book up every single manager twice or three times and basically slow the entire system down.

Will this work ?

Share this post


Link to post
Share on other sites
The problem with that is that the WndProc you would assign to each new WNDCLASSEX needs to be a static function, so you'd have to either declare a new WndProc for every class you create (which makes dynamic creation of windows impossible) or go back to having a single WndProc for all the Windows.

What you need is to be able to have a single WndProc and a system so that, within the WndProc, you can identify the specific Window class that the Proc is being called for, so you can then pass the message on to a member function of that Window class.

Once that is working, you can then create Window classes in any way you want pretty much ad hoc, and respond to window messages inside a member function of each class.

Share this post


Link to post
Share on other sites
bah this is this ridiculously confusing :( why does a teacher have to ask for something this complicated off the bat >.<

Sorry about all of this, but I do not understand . WNDPROC can be for all the Windows I understand that, but how do you manage to get the HWND's working well? more questions as I get answers I never thought it would lump down like this and my entire group basically passed me this assigment because they do nt understand it either :/

Share this post


Link to post
Share on other sites
Quote:
Original post by wijnand
bah this is this ridiculously confusing :( why does a teacher have to ask for something this complicated off the bat >.<

Sorry about all of this, but I do not understand . WNDPROC can be for all the Windows I understand that, but how do you manage to get the HWND's working well? more questions as I get answers I never thought it would lump down like this and my entire group basically passed me this assigment because they do nt understand it either :/


How do you mean, get the HWND's working properly? I thought this was working now?

You appear to have been set a very non-trivial assignment really. Wrapping the Win32 Window management API is a pretty complex issue to get right. Perhaps by posting here, we've ended up looking at this too complicated.

What exactly have you got to accomplish for your assignment?

Share this post


Link to post
Share on other sites
Basiaclly the assigment is as follows I need to make a Console prompt where the entire program starts up with. Then whenever the user wants a additional window he just presses 1 or types in new window where a Window starts up that basically renders a scene on the screen. The idea is basically that the Kernel.cpp is capable of running a infinite amount of windows on the screen in either DirectX or OPENGL.

If you close the console though the entire program should close. The idea is that basically your making multiple windows which can be rendering a completly different scene, or the same one, albeit in DirectX and OpenGL.

Share this post


Link to post
Share on other sites
As EasilyConfused points out, if you're to have one WndProc for all the windows (and this really is the easiest way), you'll need a way to determine the windows from each other.

I achieve this by having a static map of HWNDs to pointers-to-windows, so my WndProc can iterate through the whole list of HWNDs, find the window it belongs to, and call the appropriate function.

Share this post


Link to post
Share on other sites
Not at all. If you take your existing WindowManager which maintains a list of Window classes, you can just do:

psuedocode

int WndProc(HWND Hw,MSG M,etc)
{
for_each(Window W in List)
{
if(W.Hw==Hw) W.OnMessage(M);
}
}

Share this post


Link to post
Share on other sites
hmmm ok, but how would I create the windows and then put it all in a message queue? as I assume each window still needs its own emssage queue then? and the linke dlist would basically not be neccesary anymore?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this