C Board  

Go Back   C Board > Platform Specific Boards > Windows Programming

Reply
 
LinkBack Thread Tools Display Modes
Old 04-27-2009, 03:19 AM   #1
Registered User
 
Join Date: Oct 2008
Posts: 27
Question Multiple instances of classes, and passing pointers around, multithreading

Hello,

I am having a bit of a headache trying to structure my program "the right way".

This is the case:

I am making a dynamic link library, containing some resources and functions that will allow me to open a window, throw a skin on it, pass in some value from the calling language and then return. Then I will poll from the calling language to see if the window is closed, and return either a manipulated version of the value that was passed in, or a value indicating which button was pressed (message box for instance) and so on, depending on what purpose the window opened had.

The way I am trying to do things are:
I have a main source file + header that defines the export functions visible to the calling language.
I have one source file + header which defines a class for the skinning process.
I have one source file + header which defines the common functions for a window, mainly;
  • Registering the window class
  • Creating the window
  • Drawing some graphics in the window that is common to all my windows
  • Some functions for getting/setting class name, window title, size, position
I have a recouce script defining my resouces (mainly bitmaps).
I have a source file + header for each of my custom controls (they are not using classes, atm (old style C with structures, and so on))
And finally I have a source file + header for each of my different windows.

Now, it shall be possible for some of my windows to have multiple instances open at the same time, so the way I was trying to go about that was to create an instance of my classes in the DLL export function and put them inside a structure, because I am spawning a new thread for each call to my window. The process goes something like this:
  • Calling language calls my function for creating a window
  • I malloc a pointer to my structure containting pointers to my two classes
  • Creates an instance of the two classes by using the 'new' C++ keyword and assigning them to the pointers in my structure like this: structpointer->class = new Class()
  • Uses the syntax structpointer->windowclass->Function() to set title and position of my window to be created
  • Calls CreateThread passing in the pointer to my structure containing the class pointers
  • Returns

Now the function CreateThread is calling is just a wrapper that calls a WinMain-style function, with an additional parameter; the pointer to my structure with the class pointers.

Inside my WinMain-style function for my window, the following takes place:
  • I set the class name for my window using the syntax structurepointer->windowclass->Function()
  • Registering the window, passing in my structure pointer to reserve space for it in the cbWndExtra member of the WINDOWCLASSEX structure
  • Create the window, assign the pointer to my structure to the window using SetWindowLongPtr() and load my skin
  • In my callback procedure I am obtaining the pointer to my structure by calling GetWindowLongPtr() and then process messages, sending the ones that needs processing to my skin class, and processing the others locally, or inside my window class.

Is this a good way to do it? I am not sure if it will work at all... I am not deleting my classes now, for instance, I am not sure how to go about doing that. I also have to return the window handle to my calling language, in some way, so that I have a way of polling the right window for results, and also for doing cleanup on exit.

The way I initially was intending to do this was to have a class for each window too (would solve some of my cleaning up problems by using the destructor), but I ran into some paradoxes with the callback procedure not being static, and if I were to define it as static, i would run into problems with my pointers to the skin class inside the static function, and so on.

Also, I was experiencing some trouble with accessing my resources. It seemed like the calling language did not load the DLL the way I expected. I found a way to "solve" this by calling LoadLibrary("mydll.dll") from my DLL. Not sure if this is very nice to do either.

Now, do you guys have any suggestions and advices on how to do this the most elegant, and smooth way?

Feel free to flame and yell at me for not doing my homework and coming up with stupid ideas :-) I deserve it :-)

Last edited by Eirik; 04-27-2009 at 05:55 AM. Reason: More descriptive title
Eirik is offline   Reply With Quote
Old 04-28-2009, 12:53 AM   #2
Registered User
 
Join Date: Sep 2004
Location: California
Posts: 2,845
Why are you creating multiple threads for this? It seems like a very bad idea. All window handling code should be done in the main message loop thread.
bithub is offline   Reply With Quote
Old 04-28-2009, 05:10 AM   #3
Registered User
 
Join Date: Oct 2008
Posts: 27
Quote:
Why are you creating multiple threads for this? It seems like a very bad idea. All window handling code should be done in the main message loop thread.
Because if I don't, I will block the calling application until my window closes.
Eirik is offline   Reply With Quote
Old 04-28-2009, 10:26 AM   #4
Registered User
 
Join Date: Sep 2004
Location: California
Posts: 2,845
No you wont. Windows do not block, they simply return to the message loop. If your window is blocking, chances are you are creating it incorrectly.
bithub is offline   Reply With Quote
Old 04-28-2009, 11:50 AM   #5
Registered User
 
Join Date: Oct 2008
Posts: 27
Hmm.. I am creating it like this:

Code:
int APIENTRY MyWin(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow) {
	WNDCLASSEX wcex;
	HBRUSH hbrGray;
	MSG msg;

	hbrGray = CreateSolidBrush(RGB(216,216,216));

	wcex.cbSize		= sizeof(WNDCLASSEX);
	wcex.style		= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon		= NULL;
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= hbrGray;
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= "myWndClass";
	wcex.hIconSm		= NULL;
	wcex.cbWndExtra		= 0;

	RegisterClassEx(&wcex);

	HWND hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW,
                        "myWndClass",
                        "Nice title",
                        WS_OVERLAPPEDWINDOW,
                        200,
                        200,
                        190,
                        335,
                        NULL,
                        NULL,
                        hInstance,
                        NULL);

	ShowWindow(hwnd,nCmdShow);
	UpdateWindow(hwnd;

	while (GetMessage(&msg, NULL, 0, 0)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	UnregisterClass("myWndClass",GetModuleHandle(0));

	return (int) msg.wParam;
}
And it seems as though this will block the calling language until the message pump recieves a quit message and the function returns.

Note that this code resides in a DLL that the calling language is opening, and then executing. It is not a regular executable file.

Last edited by Eirik; 04-28-2009 at 11:56 AM.
Eirik is offline   Reply With Quote
Old 04-28-2009, 12:18 PM   #6
Senior software engineer
 
brewbuck's Avatar
 
Join Date: Mar 2007
Location: Portland, OR
Posts: 5,381
If your DLL is called by an application, then it can't have a message loop. There must be only one message loop in the application.

Things might be simpler if you register your window as a dialog instead of an application window.
__________________
"Congratulations on your purchase. To begin using your quantum computer, set the power switch to both off and on simultaneously." -- raftpeople@slashdot
brewbuck is online now   Reply With Quote
Old 04-28-2009, 02:34 PM   #7
Registered User
 
Join Date: Sep 2004
Location: California
Posts: 2,845
If you don't want to use a dialog window, then your DLL should call SetWindowsHookEx() to set a WH_GETMESSAGE hook. This will allow your DLL to get the window messages from the main message pump so that you can update your own windows.
bithub is offline   Reply With Quote
Old 04-28-2009, 03:34 PM   #8
Hat seller extraordinaire
 
Join Date: Apr 2008
Posts: 159
Quote:
Originally Posted by brewbuck View Post
There must be only one message loop in the application.
Since when?

Last edited by adeyblue; 04-28-2009 at 03:38 PM.
adeyblue is offline   Reply With Quote
Old 04-28-2009, 04:00 PM   #9
Registered User
 
Join Date: Sep 2004
Location: California
Posts: 2,845
Quote:
Originally Posted by adeyblue View Post
Since when?
You can create multiple message loops. I just can't fathom a case where this would be desirable.
bithub is offline   Reply With Quote
Old 04-28-2009, 04:22 PM   #10
Senior software engineer
 
brewbuck's Avatar
 
Join Date: Mar 2007
Location: Portland, OR
Posts: 5,381
Quote:
Originally Posted by adeyblue View Post
Since when?
Since programmers decided to maintain their sanity?
__________________
"Congratulations on your purchase. To begin using your quantum computer, set the power switch to both off and on simultaneously." -- raftpeople@slashdot
brewbuck is online now   Reply With Quote
Old 04-28-2009, 11:27 PM   #11
Unregistered User
 
Yarin's Avatar
 
Join Date: Jul 2007
Posts: 925
I think adeyblue just misunderstood brewbuck;
What brewbuck really meant (I think) is that there's only ever one active message loop in a program. If you do have multiple msg loops, they're always exchanging control so that only one is actually running at a time.
__________________
GCC 4.4.0, Code::Blocks 8.02, Fedora 11, x64
Yarin is offline   Reply With Quote
Old 04-29-2009, 01:57 AM   #12
Registered User
 
Join Date: Oct 2008
Posts: 27
Quote:
If you don't want to use a dialog window, then your DLL should call SetWindowsHookEx() to set a WH_GETMESSAGE hook. This will allow your DLL to get the window messages from the main message pump so that you can update your own windows.
What excactly will happen then? Will I recieve, say, a WM_ACTIVATE notification to my window if I activate the parent window?

Another obstacle I'm running into here is this:
I register my window specifiing some extra bytes at the cbWndExtra member, like this:
Code:
    wcex.cbWndExtra	    = sizeof(CSkin *) + sizeof(CWindowData *);
Then I create my window.

In my window procedure I have this code:
Code:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    CWindowData *cwp = (CWindowData *)GetClassPointer(hwnd,0);
    CSkin *csp = (CSkin *)GetClassPointer(hwnd,sizeof(CWindowData *));

    if(csp->IsHandledMessage(message)) // Is there any messages that needs to be trapped for the skinning process?
        return csp->WndProc(hwnd,message,wParam,lParam);
The problem here is that during the initiation of the window, the pointers recieved from GetClassPointer() is NULL pointers, because I haven't set them yet with this code:
Code:
cwp = new CWindowData();
csp = new CSkin();

SetClassPointer(hwnd,cwp,0);
SetClassPointer(hwnd,csp,sizeof(CWindowData *));
The Get/SetClassPointer() functions basically just sets or retrieves the pointers stored in the extra bytes (at the GWLP_USER index) associated with my window, where the last parameter is the offset from GWLP_USER.

Any suggestions how I should go about doing this? The skin class is depending on processing some early messages sent to the window, like WM_GETMINMAXINFO and WM_NCCALCSIZE.
Eirik is offline   Reply With Quote
Old 04-29-2009, 09:30 AM   #13
Unregistered User
 
Yarin's Avatar
 
Join Date: Jul 2007
Posts: 925
>> I register my window specifying some extra bytes at the cbWndExtra member, like this:
The problem though, is you're reading the window's class bytes. (e.g cbClsExtra, not cbWndExtra). To alter the window's values you should use GetWindowLong.

>> What excactly will happen then? Will I receive, say, a WM_ACTIVATE notification to my window if I activate the parent window?
No. Your hook will receive the same messages that your thread's windows receive. The hook's proc runs separately from the running msg loop.
__________________
GCC 4.4.0, Code::Blocks 8.02, Fedora 11, x64
Yarin is offline   Reply With Quote
Old 04-29-2009, 10:33 AM   #14
Registered User
 
Join Date: Oct 2008
Posts: 27
Quote:
The problem though, is you're reading the window's class bytes. (e.g cbClsExtra, not cbWndExtra). To alter the window's values you should use GetWindowLong.
The Get/SetClassPointer are my functions, they are just wrapping Get/SetWindowLong.
Eirik is offline   Reply With Quote
Old 04-29-2009, 01:54 PM   #15
Unregistered User
 
Yarin's Avatar
 
Join Date: Jul 2007
Posts: 925
Right. Sorry about that.

What I would do is this:
-> Create the window initially invisible.
-> Tell your WndProc to just return zero on the WM_CREATE and WM_NCCREATE messages.
-> Call that SetClassPointer chunk of code you have there.
-> Send a custom WM_USER message to your window. In the handler for this message, you would have everything that you previously had in the WM_CREATE case. This is were you would also then make the window visible and active using ShowWindow.
__________________
GCC 4.4.0, Code::Blocks 8.02, Fedora 11, x64
Yarin is offline   Reply With Quote
Reply

Tags
c++, class, pointer, windows

Thread Tools
Display Modes

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Terrible confusion with time variables LowlyIntern C++ Programming 12 08-01-2008 07:23 AM
C++ Classes: Use, Misuse...Confusion. Snorpy_Py C++ Programming 4 10-23-2006 01:46 AM
for loop confusion Enges C++ Programming 6 04-26-2006 08:21 AM
Server-net newbie confusion geek@02 Windows Programming 1 04-28-2005 02:08 AM
confusion with increment and decrement operators cBegginer C Programming 6 03-19-2005 03:45 PM


All times are GMT -6. The time now is 09:28 PM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.3.0 RC2

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22