Results 1 to 9 of 9
  1. #1
    Join Date
    Oct 2006
    Posts
    19

    Req for Help: Device Context causing Access Violation

    Hi,
    I'm midway through VTM 5.5 getting the game into a windows application and I've hit a bit of a snag:
    Unhandled Exception / Access Violation.

    I get this when I try to access the memory location at winCanvas here:
    Code:
    void DrawEngine::drawBackground(void)
    {
    	wxMemoryDC dc; // Device context
    HERE>  dc.SelectObject(*winCanvas); // Select the canvas to draw on.
    	
    	// If we have a map:
    	if (map)
    	{
                   *snip*
    	}
    
    	dc.SelectObject(wxNullBitmap); // De-associate the DC. Avoids memory leaks.
    }
    I've tried running through the whole thing line by line up until that point to see if I could point out any inconsistancies, but got nothing. I also knew of the issue where you need to de-select the object once your done with it and as far as I know, this DC.SelectObject is the first in the program.

    As I'm not sure where the problem could possibly lie, I don't know what code to paste in here that would help. I have uploaded a zipped version you can open in VS08 HERE. I would be grateful for any advise on where else to look for the error if you are unable to sift through the code yourself.

    Thanks muchly!
    *Goes back to staring at his broken code*

  2. #2
    Join Date
    Jun 2003
    Location
    Trier, Germany
    Posts
    1,350
    a general advice here:

    winCanvas is potentially uninitialized, which is bad! ensure that your members always remain in a valid state! in this case that means, initialize winCanvas to NULL in the constructor and check for !NULL whenever you're trying to dereference the pointer.
    the vtms seem to be a little sloppy on those things, so be sure to add such code by yourself while you go along - should be an excellent exercise to ensure you really understand what the code is doing

    again: don't ever leave members in undefined state. things like that will kill you faster than you can say "c++"...

  3. #3
    Join Date
    Oct 2006
    Posts
    19
    Thanks for the advice mate. I'll make sure to keep that in mind.
    While winCanvas is declared, I don't think it was ever specifically initialized. I tried initializing it to NULL (winCanvas = NULL but that had little effect.
    Any other ideas?

  4. #4
    Join Date
    Jun 2003
    Location
    Trier, Germany
    Posts
    1,350
    you checked whether wincanvas is valid upon dereferencing?

  5. #5
    Join Date
    Oct 2006
    Posts
    19
    Quote Originally Posted by ComicSansMS View Post
    you checked whether wincanvas is valid upon dereferencing?
    How would one do that? Sorry, I'm still grasping the whole referencing/dereferencing stuff.

  6. #6
    Join Date
    Jun 2003
    Location
    Trier, Germany
    Posts
    1,350
    k, the whole thing is about statements like this:
    Code:
    *winCanvas
    what you're doing here is dereferencing the pointer, which means you tell the compiler: go to whatever location in memory the pointer points to and interpret the data there as type wxBitmap. which of course only makes sense, if the pointer really *is* pointing to a wxBitmap.

    the easiest way to find out when debugging is mouse-over winCanvas in debug-mode. if the debugger can resolve the pointer, you will be able to view the contents of the object, if not the compiler will complain.
    since the end-user is unlikely to have a debugger running, it is mandatory to ensure that your pointers are pointing to valid objects before dereferencing.
    you could do something like this:

    Code:
    DrawEngine::DrawEngine(): wxBitmap(NULL) [...]
    
    void DrawEngine::drawBackground()
    {
    	wxMemoryDC dc; // Device context
    	if(!winCanvas) {
    		//error, pointer invalid!
    		//todo: error handling;
    		exit(1);
    	}
    	dc.SelectObject(*winCanvas); // Select the canvas to draw on.
    	[...]
    }
    provided that all member functions of DrawEngine guarantee winCanvas is either NULL or a pointer to a valid wxBitmap, this test will keep you from dereferencing garbage pointers. be aware though that this condition is easily violated if your code is sloppy. conditions like this which remain valid at all times for all member functions are called class invariants. this is not a language feature, but more of a guideline to help you not to mess things up while implementing (though there exist many tools that allow automated checking of class invariants through language features of c++, but that's a little advanced right here).

    for now:
    1. check all member functions of DrawEngine to ensure that none of them is doing something unexpected to winCanvas (i.e. setting it to anything but NULL or the address of a valid wxBitmap).
    2. check all occassions where winCanvas is dereferenced and make sure you test for NULL before performing the derefencing.
    3. if the pointer still ends up in undefined states, ensure that wxBitmap is not accidentally deleted by a third party. consider the following code:
    Code:
    void SetBitmap(DrawEngine* drawArea)
    {
    	wxBitmap my_bitmap;
    	drawArea->setWindow(&my_bitmap, 100, 100);
    }
    since my_bitmap is a local object, the pointer passed to setWindow will become invalid as soon as you leave SetBitmap(). there goes your precious class invariant...
    more subtle errors may occur, so be sure to keep good track of your pointers.

  7. #7
    Join Date
    Oct 2006
    Posts
    19
    Great information mate, thanks! I know it can be hard repeating this somewhat basic stuff over and over again.

    In the end it looks like I had some redundant code performing an operation on winCanvas that should have been cut into a new function. Instead it was copied. This meant it was being called and used before it was meant to and was hidden by the fact that the error only popped up when it tried to perform the same operation for the second time.
    Needless to say, it was a bit of a head slapper. I daresay this happened because I just didn't design this code structure. I am merely copying it from the VTMs and learning what I can while I go. I think when I start programming from my own brain this sort of thing will happen less as I get to know my own code.

    Not to matter, I spent quite a few days going over and over your advise and other pointer theory. So I've learnt a bit from this silly mistake, which is all I can ask for hah.

    Thanks again.

  8. #8
    Join Date
    Jun 2003
    Location
    Trier, Germany
    Posts
    1,350
    Quote Originally Posted by djdoomsday View Post
    Needless to say, it was a bit of a head slapper. I daresay this happened because I just didn't design this code structure. I am merely copying it from the VTMs and learning what I can while I go. I think when I start programming from my own brain this sort of thing will happen less as I get to know my own code.
    Full ack on that one. Copying code is sometimes a necessity when learning, but you will probably end up with large portions of code that you don't fully understand. If you have the time and motivation, feel free to re-implement the whole project from scratch once you finished the VTMs. It'll not only be an excellent exercise but it will also provide you with a larger code project that you can come back to and try newly learned concepts on.

  9. #9
    Join Date
    Oct 2006
    Posts
    19
    Aye. I mean I am manually writing out each line from the VTMs and I usually try to comment every line in an attempt to actually remember it all. But its the way they've done the VTMs that throws me off - They start in a highly linear state and then progressively OO it by replacing chunks of code with functions, and that confuses me because the way they initially design the app is wrong imo. I would have made it much more OO right from the get-go. It means I have to keep relearning how they're designing the app on a high level.
    It also means they do a fair bit of cutting and pasting of code from one place to another. This error was all because i copied instead of cut.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •