Thread: C++ confusion

  1. #1
    Registered User
    Join Date
    Oct 2008
    Posts
    34

    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

  2. #2
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    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.

  3. #3
    Registered User
    Join Date
    Oct 2008
    Posts
    34
    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.

  4. #4
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    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.

  5. #5
    Registered User
    Join Date
    Oct 2008
    Posts
    34
    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.

  6. #6
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    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.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  7. #7
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    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.

  8. #8
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    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.

  9. #9
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    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.

  10. #10
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by adeyblue View Post
    Since when?
    Since programmers decided to maintain their sanity?
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  11. #11
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    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.

  12. #12
    Registered User
    Join Date
    Oct 2008
    Posts
    34
    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.

  13. #13
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    >> 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.

  14. #14
    Registered User
    Join Date
    Oct 2008
    Posts
    34
    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.

  15. #15
    Unregistered User Yarin's Avatar
    Join Date
    Jul 2007
    Posts
    2,158
    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.

Popular pages Recent additions subscribe to a feed

Similar Threads

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

Tags for this Thread