Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

MDI Problem

Posted on 2004-08-01
14
Medium Priority
?
447 Views
Last Modified: 2012-05-05
I am trying to create an MDI application, i have managed to get everything working fine by creating the main window with MDI frame, then i created an MDI client - all worked well until i tried creating multiple MDI clients, they both loaded but variables such as socket's where shared between them so they used the same ones (DOH), this was because i had them all set as global variables, to fix this i spent ages re-writing the child window to have all the code inside a class so i could create a new instance of the class for each window and therefore get different variables. This didn't work because the WndProc has to be static, therefore the variables have to be static, and that means that if i create 2 instances of the class then they still share the same damn variables... so quite simply, how the hell am i meant to get 2 MDI children (or more) that use different variables? so i can open 100 windows if i want and they will each have their own variable called "s" or whatever
0
Comment
Question by:_KM_
  • 8
  • 6
14 Comments
 
LVL 19

Accepted Solution

by:
mrwad99 earned 120 total points
ID: 11687845
>> so quite simply, how the hell am i meant to get 2 MDI children (or more) that use different variables?

I take it you mean MDI child windows that reside within the one CFrameWnd.  In this case, simply add variables to the view or the document class and access them either via public methods or via a pointer to your view/document obtained via GetActiveView() or GetDocument() respectively.

HTH
0
 
LVL 1

Author Comment

by:_KM_
ID: 11688244
I created the windows via the win32 API and not via all that MFC stuff...
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 11688274
In that case then you just need to add the variables to whatever class or code you have representing the window.  You could add a struct that contains all the variables, eg

typedef struct myWindStructTAG
{
     int iVar1;
     int iVar2;
     UINT uSomethingelse;
}myWindStruct;

and then whenever creating a new window simply give it one of these with all the variable values filled in appropriately
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 1

Author Comment

by:_KM_
ID: 11692867
how would i assign it to the window? i cant put it in the class because as its a static variable it would share it over all the instances of the class, and i tried using the user data part of the windows properties to store it but it just came up with memory write errors
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 11695060
You must be creating an instance of some window or some object that represents each MDI child.

>> i cant put it in the class because as its a static variable

You don't want it to be static if you want each child to have one of these structs.  Post the code that you are calling to create a new MDI child window and I will have a look, although I am not too good at this since it is API and not MFC.
0
 
LVL 1

Author Comment

by:_KM_
ID: 11695751
I have a thread for each window       which creates the class and then sits there waiting for the window to be closed before destroying the class

typedef struct THREADSTRUCT
{
    ChannelWindow*    ThisThing;
        //you can add here other parameters you might be interested on
} THREADSTRUCT;

ChannelWindow wind;
      wind.window(data.channame, data.username);
      while(wind.active) Sleep(100);
      return 0;

and the ChannelWindow class is : (partial code, the entire file is way too big)

int windcount;
class ChannelWindow
{
private:
      HWND wind;
      SOCKET theSock;
      DWORD dwUPKey, dwDWKey;
public:
      void OpenChatClient();
      static LRESULT CALLBACK ChanWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
};



LRESULT CALLBACK ChannelWindow::ChanWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
      if (GetWindowLong(hwnd, GWL_USERDATA) == 0)
            return DefMDIChildProc(hwnd,msg,wParam,lParam);
      if (msg == 6666)      // Custom Window creation
      {
            // ... Code for creating all the other stuff such as buttons
      }
      else if (msg == WM_SIZE)      // Window resize      
      {
            //... Resize stuff
      }
      return DefMDIChildProc(hwnd,msg,wParam,lParam);
}



void ChannelWindow::OpenChatClient()
{
      CString Name;
      Name.Format( "CLIENT%d", windcount);
      WNDCLASSEX wc;
      wc.cbSize             = sizeof(WNDCLASSEX);      // size of class object (there are 2 types of class object)
      wc.style             = 0;      // style 0
      wc.lpfnWndProc       = ChanWndProc;      // the event handler function (ChanList in this case, see above)
      wc.cbClsExtra       = 1;      // additional options
      wc.cbWndExtra       = 2;      // additional options
      wc.hInstance       = Instance;      // the program? NULL! hahaha
      wc.hIcon             = LoadIcon(NULL, IDI_APPLICATION);      // icon to use
      wc.hCursor             = LoadCursor(NULL, IDC_ARROW);      // cursor to use
      wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);      // background
      wc.lpszMenuName  = NULL;      // menu bar to use (yeh right...)
      wc.lpszClassName = Name;      // name of the class
      wc.hIconSm             = LoadIcon(NULL, IDI_APPLICATION);      // "small" icon to use (top left cornet one)

      if(!RegisterClassEx(&wc))      // register the class
      {
            MessageBox(NULL, "Client Registration Failed!", "Error!",      // error message
                  MB_ICONEXCLAMATION | MB_OK);
      }


      MDICREATESTRUCT mcs;
      HWND hChild;
      
      // set up the window options

      mcs.szTitle = chan;                              // the window title
      mcs.szClass = Name;      // name of the class
      mcs.hOwner  = GetModuleHandle(NULL);      // window owner
      mcs.x = mcs.cx = CW_USEDEFAULT;                  // default positions
      mcs.y = mcs.cy = CW_USEDEFAULT;                  // default positions
      mcs.style = MDIS_ALLCHILDSTYLES;            // style to use (all)
      hChild = (HWND)SendMessage(MDI, WM_MDICREATE, 0, (LONG)&mcs);      // tell MDI frame to make me a window
      if(!hChild)      // Error handler
      {
            MessageBox(MDI, "Error Loading WIndow", "Error!",      // Damn it!
                  MB_ICONEXCLAMATION | MB_OK);
      }
      wind=hChild;

      THREADSTRUCT* thingie;
      SetWindowLong(hChild, GWL_USERDATA, (LPARAM) &thingie);       // set this class in user data
      SendMessage(hChild, 6666,0,0);               // Tell it to create buttons etc
      return;
}



basicly it should register a class and create the window using a different class name each time (CLIENT<number>) that was because of my attempts to get the classes registered to use a different WndProc for each one (didn't work) it then sends a message to set "this" (pointer to this instance of the class) as the user data for the window, then sends a message 6666 to create the window (as the default create is executed before the user data is set i need to create after instead) it creates the window fine and the user data contains a pointer to the THREADSTRUCT that contains the pointer to the class, but the problem is if i try to use:

THREADSTRUCT*    ts = (THREADSTRUCT*)GetWindowLong(GetParent(hwnd), GWL_USERDATA);
then access the socket for example using ts->ThisThing->theSock

in theory i figure that should work, but it comes up with a memory write error - the source and target addresses are similar which would imply its not far off on the address it wants but it wont work
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 11696779
>> THREADSTRUCT*    ts = (THREADSTRUCT*)GetWindowLong(GetParent(hwnd), GWL_USERDATA);

Now I am not sure as to API as I have said, but if you put an ASSERT(ts) after this line you will probably find that ts is NULL, in which case it is no surprise that you get a memory access violation.

Recheck your code and ensure that you have correctly initialised what you are trying to cast here.

I will be honest now (as always) I am not the best person to ask and the Windows Programming area would have been a better place to ask this question methinks.  You may be best advised to post a pointer question in that TA to this question.

HTH
0
 
LVL 1

Author Comment

by:_KM_
ID: 11696833
its not NULL, the u checked that with a message box using:
CString temp
temp.Format("%d", ts) and got a number from it, and the address access is not trying to access address 00000000 its accessing somewhere near to the address of the function thats calling it
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 11696925
I am surprised that even compiles looking at it again, since theSock is a private member of the ChannelWindow instance (here 'ThisThing').  Break it down into smaller chunks also:

THREADSTRUCT*    ts = (THREADSTRUCT*)GetWindowLong(GetParent(hwnd), GWL_USERDATA);  // OK
ASSERT();

ChannelWindow* pChannelWindow = ts->ThisThing;
ASSERT(pChannelWindow);

SOCKET* pSocket = PChannelWindow->theSock;
ASSERT(pSocket);

But like I say the last line should not work since theSock is a private member...




0
 
LVL 19

Expert Comment

by:mrwad99
ID: 11696930
Correction:

>>THREADSTRUCT*    ts = (THREADSTRUCT*)GetWindowLong(GetParent(hwnd), GWL_USERDATA);  // OK
>> ASSERT(ts );
0
 
LVL 1

Author Comment

by:_KM_
ID: 11702940
It did compile, although as i said that was a reduced version of the code so perhaps i missed something important out with the bits i removed that allows it to work...

I had anouther idea of simply creating an array of 1000 for each variable (ie, SOCKET theSock[1000] etc) and then use

// global defenition
int number;

// in the window create
SetWindowLong(clienthwnd, GWL_USERDATA, number);
number++;

//then to access the socket use
theSock[GetWindowLong(clienthwnd, GWL_USERDATA)]

in theory this should work for the first 1000 child windows opened - and if someone plans on using it more than that then i doubt they would mind restarting every now and then, heh

I am just in the middle of going through the 2000 lines of code for the MDI child and so far i'm down to 91 compile errors :-) in a few hours i'll get down to 0 and i'll be able to see if it works or not... heh
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 11703578
That would be an outrageous hack.  Did you try the ASSERTs that I suggested ?
0
 
LVL 1

Author Comment

by:_KM_
ID: 11705772
i got it working, and its not very memory intensive, probibly because the array items aren't initialised until they are used and are they destroyed when they're finished with, its using just over 4MB of RAM, it was at 3.9MB before so... lol

i did try the assert, but oh well...

i got it working now, thanks anyway :-)
0
 
LVL 19

Expert Comment

by:mrwad99
ID: 11707818
Well, I am glad you got it sorted.
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.
Suggested Courses

916 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question