Thread: Win32, Tracking data with MDI's

  1. #1
    Registered User
    Join Date
    Jul 2005
    Posts
    7

    Win32, Tracking data with MDI's

    Hey, I posted this in coding forums as well, but with no luck. I'm currently trying to make a program that uses an MDI, but I've hit a deadend I can't figure out how to keep track of each set of data, that goes along with the correct MDI child window.

    I have a struct that stores information about a document, and an array of these structs, one for each open child window. When a window needs repainting, I want to be able to pull the correct data for the window. I tried giving each struct for the document a handle variable, and testing for it, but to no avail. Somebody suggested about giving the MDI's a new member variable for storing the struct, but I don't have a clue about how to go about that

    If anybody has any advice, or help they can give me, I'd really appreciate it. I hope I've explained it enough.

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> I tried giving each struct ... a handle variable ... but to no avail.
    That's sounds perfectly reasonable to me. If each struct contains the window handle of the corresponding MDI child, then you'll be able to lookup the correct struct during WM_PAINT messages of the MDI child.

    If you can't get that to work, post your code.

    If you haven't been through the MDI reference material, read through the "Overviews" links here: http://msdn.microsoft.com/library/de...tinterface.asp

    gg

  3. #3
    Registered User
    Join Date
    Jul 2005
    Posts
    7
    I must be doing something wrong I can't get it to work.

    Here is the code from the WM_PAINT message:
    Code:
    	// Do tha junk
    	PAINTSTRUCT ps;
    	HDC			hdc;
    
    	// simply validate the window 
    	hdc = BeginPaint(hwnd,&ps);	 
    
    	// paint board
    	hdc = PaintBoard(hwnd, hdc);
    
    	// end painting
    	EndPaint(hwnd,&ps);
    The PaintBoard function:
    Code:
    HDC PaintBoard(HWND hChild, HDC hdc)
    {
    	// Get DC
    	if(!hdc)
    	{
    		HDC hdc = GetDC(hChild);
    	}
    
      	// Get the right circuit data
    	Circuit CircuitData = GetCircuitData(hChild);
    
    	// setup tools
    	HBRUSH brush;
    	HPEN pen;
    			
    	// Paint background
    	brush = CreateSolidBrush(CircuitData.bgcolor);
    	SelectObject(hdc, brush);
    	Rectangle(hdc, 0, 0 , CircuitData.size.width + (DOC_BORDER*2), CircuitData.size.height + (DOC_BORDER*2));
    
    	// Paint Board
    	brush = CreateSolidBrush(RGB(0,0,0));
    	SelectObject(hdc, brush);
    	Rectangle(hdc, DOC_BORDER+5, DOC_BORDER+5, CircuitData.size.width+5, CircuitData.size.height+5);
    	brush = CreateSolidBrush(CircuitData.color);
    	SelectObject(hdc, brush);
    	pen = CreatePen(PS_SOLID, 1, RGB(0,0,0));
    	SelectObject(hdc, pen);
    	Rectangle(hdc, DOC_BORDER, DOC_BORDER, CircuitData.size.width, CircuitData.size.height);
    
    	// End it
    	return hdc;
    }
    The function used within that, to try for the data using the handle:
    Code:
    Circuit GetCircuitData(HWND hTest)
    {
    	for(int i = 0; i < NumCircuits; i++)
    	{
    		if(circuits[i].handle == hTest)
    		{
    			break;
    		}
    	}
    	// Get the right circuit data
    	return circuits[i];
    }
    I have set circuits as a global array of the Circuit structs, and NumCircuits as the number of current windows. Here is the struct:

    Code:
    // A circuit
    struct Circuit
    {
    	HWND handle;
    	const char* title;
    	const char* began;
    	const char* notes;
    	const char* todo;
    	COLORREF color;
    	COLORREF bgcolor;
    	Version version;
    	Size size;
    	Component comps[500];
    	Textbox texts[100];
    	Wire wires[3000];
    };
    It doesn't seem to supply the right data. The board isn't drawn correctly, and to test it I replaced the break in the handle check loop with a messagebox, and it returned for every window. Cheers

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    The first thing I notice is that GetCircuitData() is returning the Circuit struct by value. This means that any modifications made to that structure will not be reflected within the global circuits[] array.
    Second, your GetCircuitData() function should handle cases where it doesn't find the given HWND:
    Code:
    Circuit* GetCircuitData(HWND hTest)
    {
        for (int i = 0; i < NumCircuits; ++i)
        {
            if (circuits[i].handle == hTest)
            {
                return &circuits[i];
            }
        }
        
        const char *msg = "GetCircuitData() failed";
        MessageBoxA(0, msg, msg, MB_OK);
    
        return 0;
    }
    Having proper error checking in your code will help to track down issues much easier and faster.

    If you're still having problems, them post your code that adds to the circuits array (window creation) and removes from the circuits array (windows destruction) along with your modifed GetCircuitData() and any code that calls it.

    gg
    Last edited by Codeplug; 07-04-2005 at 09:53 AM.

  5. #5
    Registered User
    Join Date
    Jul 2005
    Posts
    7
    Wahey, It's working ^_^

    Cheers, I used a pointer instead, and fiddled with the handle assigning a bit, and it works like a charm

    Cheers, Again Mate, A real saviour

  6. #6
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    watch the possible dangling pointer (should not be a problem) and lost GDI objects in PaintBoard()

    (unless you are using a .NET version of MSVC)
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  7. #7
    Registered User
    Join Date
    Jul 2005
    Posts
    7
    Hey, I was wondering if you could help me again. In the WM_PAINT code, when I try to show the title (though GDI or a message box), it messes up the text, and I just get a series of "Ý"'s. The title is a const char* in the struct.

    Here's the code I'm using:
    Code:
      	// Get the right circuit data
    	Circuit *pCircuitData = GetCircuitData(hChild);
    
    	Circuit CircuitData  = *pCircuitData;
    
    	// setup tools
    	HBRUSH brush;
    	HPEN pen;
    			
    	// Paint background
    	brush = CreateSolidBrush(CircuitData.bgcolor);
    	SelectObject(hdc, brush);
    	Rectangle(hdc, 0, 0 , CircuitData.size.width + (DOC_BORDER*2), CircuitData.size.height + (DOC_BORDER*2));
    
    	// Paint Board
    	brush = CreateSolidBrush(RGB(0,0,0));
    	SelectObject(hdc, brush);
    	Rectangle(hdc, DOC_BORDER+5, DOC_BORDER+5, CircuitData.size.width+5, CircuitData.size.height+5);
    	brush = CreateSolidBrush(CircuitData.color);
    	SelectObject(hdc, brush);
    	pen = CreatePen(PS_SOLID, 1, RGB(0,0,0));
    	SelectObject(hdc, pen);
    	Rectangle(hdc, DOC_BORDER, DOC_BORDER, CircuitData.size.width, CircuitData.size.height);
    
    
    	MessageBoxA(0, CircuitData.title, CircuitData.title, MB_OK);
    I know I've done something wrong because I've came across it before, I just can't remember how I fixed it.
    Last edited by Darkmonkey; 07-07-2005 at 12:37 PM.

  8. #8
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    try...

    don't
    Circuit CircuitData = *pCircuitData;

    then just
    pCircuitData->title
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  9. #9
    Registered User
    Join Date
    Jul 2005
    Posts
    7
    Nope, still no luck. Still messes up the string. I think it might have been because there is no NULL terminator? but I don't know how to add one, if it is missing.

  10. #10
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Let's see the code where you actually set the title member.

    gg

  11. #11
    Registered User
    Join Date
    Jul 2005
    Posts
    7
    Opps, sorry, forgot about that

    It's taken from a XML file. (Using TinyXMl). This codes gets the title, and sets it:

    Code:
    		// XML
    		TiXmlDocument	*xmlDoc = new TiXmlDocument(szFileName);
    		if (!xmlDoc->LoadFile())
    		{
    			MessageBox(hClient, "XML file load failed.", "Oh Oh...",MB_ICONEXCLAMATION | MB_OK);
    			return 0;
    		}
    
    		// Get root
    		TiXmlElement* xCircuit = xmlDoc->FirstChildElement("circuit");
    		if (!xCircuit)
    		{
    			MessageBox(hClient, "XML root circuit element couldn't be found", "Oh Oh...",MB_ICONEXCLAMATION | MB_OK);
    			xmlDoc->Clear();
    			delete xmlDoc;
    			return 0;
    		}
    
    		//--- Get doc data --------------------------------------------------//
    		TiXmlElement* xDoc = XMLGetElement(xCircuit, "doc");
    
    		// try for the title?
    		// IT FOOCKING WELL WORKS!
    		TiXmlElement* xTitle = XMLGetElement(xDoc, "title");
    		CircuitData.title = XMLStringVal(xTitle);
    Using this two XML wrapper functions:
    Code:
    //------------------------------------------------------------------------------------//
    // XMLGetElement()
    //------------------------------------------------------------------------------------//
    TiXmlElement* XMLGetElement(TiXmlElement* xParent, const char* ElementName)
    {
    	TiXmlElement* xElement = xParent->FirstChildElement(ElementName);
    	if (!xElement)
    	{
    		MessageBox(hClient, strcat("XML data couldn't be found for: ", ElementName), "Oh Oh...",MB_ICONEXCLAMATION | MB_OK);
    		return 0;
    	}
    	return xElement;
    }
    //------------------------------------------------------------------------------------//
    
    //------------------------------------------------------------------------------------//
    // XMLStringVal()
    //------------------------------------------------------------------------------------//
    const char * XMLStringVal(TiXmlElement* xElement)
    {
    	const char *ElementValue = (xElement->FirstChild())->Value();
    	if (!ElementValue)
    	{
    		MessageBox(hClient, "Error extracting XML string value", "Oh Oh...",MB_ICONEXCLAMATION | MB_OK);
    		return 0;
    	}
    	return ElementValue;
    }
    //------------------------------------------------------------------------------------//
    After the title is set in CircuitData.title, the CircuitData struct gets passed to a function to create the doc:
    Code:
    hOpen = MakeNewDoc(hClient, CircuitData);
    And heres that function:
    Code:
    HWND MakeNewDoc(HWND hClient, Circuit CircuitData)
    {
    	MDICREATESTRUCT	mcs;
    	HWND			hChild;
    	
    	// temp
    	COLORREF BackgroundColor = DOC_DEF_BGCOLOR;
    
    	mcs.szTitle = CircuitData.title;
    	mcs.szClass = CHILD_CLASS_NAME;
    	mcs.hOwner  = GetModuleHandle(NULL);
    	mcs.x = CW_USEDEFAULT;
    	mcs.cx = CircuitData.size.width + (DOC_BORDER*2);
    	mcs.y = CW_USEDEFAULT;
    	mcs.cy = CircuitData.size.height + (DOC_BORDER*2) + 25; // +25 for title bar etc..
    	mcs.style = MDIS_ALLCHILDSTYLES;
    	mcs.lParam = NumCircuits;
    
    	hChild = (HWND)SendMessage(hClient, WM_MDICREATE, 0, (LONG)&mcs);
    	if(!hChild)
    	{
    		MessageBox(hClient, "MDI Child creation failed.", "Oh Oh...",MB_ICONEXCLAMATION | MB_OK);
    	}
    
    	// Add to circuit count
    	CircuitData.handle = hChild;
    	circuits[NumCircuits] = CircuitData;
    	NumCircuits++;
    
    	return hChild;
    }
    Now setting the Window title using the CircuitData.title works there, but in the WM_PAINT, when I call the PaintBoard function above, the title is messed up.

    EDIT: And heres the function I call to get the circuit data in WM_PAINT:
    Code:
    Circuit* GetCircuitData(HWND hTest)
    {
        for (int i = 0; i < NumCircuits; ++i)
        {
            if (circuits[i].handle == hTest)
            {
                return &circuits[i];
            }
        }
        
        const char *msg = "GetCircuitData() failed";
        MessageBoxA(0, msg, msg, MB_OK);
    
        return 0;
    }
    //------
    Cheers
    Last edited by Darkmonkey; 07-08-2005 at 09:01 AM.

  12. #12
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> const char *ElementValue = (xElement->FirstChild())->Value();
    The string returned by the TiXmlNode::Value() method is only valid for the lifetime of the TiXmlNode object. And it may not even be valid for that long - I'm not familiar with tiny xml.

    You need to create and manage your own buffers for your Circuit structure strings or just use std::string.

    gg

  13. #13
    Registered User
    Join Date
    Jul 2005
    Posts
    7
    Wahey, You're right, I wasn't aware about lifetimes. I've managed now, by removing the code that kills the XML object, but I'll have to look into my own buffer as you said (not really sure about that at the mo).

    Cheers ^_^

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Lame null append cause buffer to crash
    By cmoo in forum C Programming
    Replies: 8
    Last Post: 12-29-2008, 03:27 AM
  2. Replies: 3
    Last Post: 04-18-2008, 10:06 AM
  3. WIN32 API: RichEdit control RTF data size
    By wn00 in forum Windows Programming
    Replies: 2
    Last Post: 09-05-2006, 06:15 PM
  4. [question]Analyzing data in a two-dimensional array
    By burbose in forum C Programming
    Replies: 2
    Last Post: 06-13-2005, 07:31 AM
  5. All u wanted to know about data types&more
    By SAMSAM in forum Windows Programming
    Replies: 6
    Last Post: 03-11-2003, 03:22 PM