Solved

GetDlgItem() casting. RONSLOW.....

Posted on 2000-02-28
31
770 Views
Last Modified: 2013-11-20
I have been reading through the entire Attn: RONSLOW... thread, and I have used this "bad" programming techninque, due to not knowing better, as you call it. What problems can come out of it? I have received input from some users that the program crashes for them, and they are running Norton crashguard, is this the kind of problem one can get when casting GetDlgItem()?
0
Comment
Question by:joakimf
  • 9
  • 9
  • 7
  • +4
31 Comments
 
LVL 8

Expert Comment

by:VinExpert
Comment Utility
Interesting.....

VinExpert
0
 
LVL 1

Author Comment

by:joakimf
Comment Utility
Adjusted points to 100
0
 
LVL 12

Expert Comment

by:migel
Comment Utility
Hi!
Casting GetDlgItem to the particulat wnd class is not safe by default! (since you cast from the base class to the derived one - you can read this in the any C++ book)
In the MFC this technique work due to MFC control classes do not contain any data and work with native windows control through window message by SendMessage API method. In this case you can crash only if you call method specific for one window class for the wrong control (!!!! and this message use pointer to data that receiver is not understand !!! - in other case you just get unpredictable results).

Using DDX_Control or SubclassDlgItem in the parent window class will be better way.
0
 
LVL 1

Author Comment

by:joakimf
Comment Utility
Thanks for your comment <miguel>, but what you commented was exactly the same thing as <RONSLOW> and a couple of other experts discussed in:
http://www.experts-exchange.com/jsp/qShow.jsp?ta=mfc&qid=10300760

According to my opinion <RONSLOW> convinsed me and I am probably going to change to DDX_Control. I just wonder if it is something that a program like Norton Crashguard picks up, and therefore the program crashes. Because the program runs just fine on other computers, but when crashguard is installed, BOOM.
0
 
LVL 3

Expert Comment

by:SamHobbs
Comment Utility
If it only crashes when Crashguard is running then it sounds like a problem with Crashguard. Has this been reported to Norton?
0
 
LVL 3

Expert Comment

by:SamHobbs
Comment Utility
If it only crashes when Crashguard is running then it sounds like a problem with Crashguard. Has this been reported to Norton?
0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
joakimf, you're really jumping to a conclusion and skipping lots of steps! You're just saying "this app crashes", and you're deciding it must be because of something you recently read.

That's very unwise. You need to do some debugging. Are you even using GetDlgItem() on any of the classes which are known to cause problems?

Why does the program crash only when Norton CrashGuard is running? What does Norton CrashGuard do to make the program sick?

..B ekiM
0
 
LVL 2

Expert Comment

by:paulburns
Comment Utility
This is getting a bit ridiculous, its gone from an interesting technical discussion to mass-panic.
0
 
LVL 2

Expert Comment

by:paulburns
Comment Utility
This is getting a bit ridiculous, its gone from an interesting technical discussion to mass-panic.
0
 
LVL 10

Accepted Solution

by:
RONSLOW earned 200 total points
Comment Utility
mike: my little sample app only crashed with BoundsChecker because MFC deliberatly turns off its own memory checking for the temporary window objects, so you don't get a crash in normal MFC/VC debug run.  But when bounds checker is wathing things the error (which is real) gets picked up.

So, similarly, it is quite possible the CrashGuard is correctly picking up a memory corruption that is not causing a direct crash in the exe (the corrupted memory is not directly being used).  That it isn't crasing without CrashGuard doesn't mean there is no problem, or that there won't be one in the future.

Whether or not it is due to the problems that happen when GetDlgItem is cast to an inappropriate Cwd-derived class one cannot comment on until one examines the code.

If you only cast to the simplest MFC control wrapper classes (eg CListBox and not CDragListBox etc), then it is probably not a problem.  Cannot comment without seeing your source code.

You might like to try using the template class I suggested, as it does about the same amount of processing as GetDlgItem does, but is safer.

Here is the template class:

template <class T> class CGetDlgItem {
public:
    CGetDlgItem(int id, CWnd* pWnd)
        : m_bUseTemp(false)
        , m_pT(NULL)
    {
        HWND hwnd =NULL;
        pWnd->GetDlgItem(id,&hwnd);
        CWnd* pDlgItem = CWnd::FromHandlePermanent(hwnd);
        if (pDlgItem) {
            ASSERT(pDlgItem->IsKindOf(m_tempT.GetRuntimeClass()));
            m_pT = (T*)pDlgItem;
            m_bUseTemp = false;
        } else {
            m_pT = &m_tempT;
            m_pT->Attach(hwnd);
            m_bUseTemp = true;
        }
    }
    ~CGetDlgItem() {
        if (m_bUseTemp) {
            m_pT->Detach();
        }
    }
    operator T* () {
        return m_pT;
    }
    T* operator-> () {
        return m_pT;
    }
private:
    bool m_bUseTemp;
    T* m_pT;
    T m_tempT;
};

and you use it like this
  CGetDlgItem<CCheckListBox> pCheckListBox1(IDC_LIST1,this);
instead of GetDlgItem like this:
  CCheckListBox* pCheckListBox1 = (CCheckListBox*)GetDlgItem(IDC_LIST1);


0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
RONSLOW> Whether or not it is due to the problems that happen when GetDlgItem
 RONSLOW> is cast to an inappropriate Cwd-derived class one cannot comment on
 RONSLOW> until one examines the code.

Exactly. I can't see where joakimf has done _any_ analysis. As far as I can tell, he's got a program that's crashing and thinks that because "some people say my program is crashing", bad casting of the GetDlgItem() return is likely.

Fact is, the first symptom of the GetDlgItem() return value being cast incorrectly is probably going to be that _the code doesn't work as expected_. Your example overwrote some memory, sure. It called a member of CCheckedListBox, even though no CCheckedListBox existed.

A programmer who wrote that code would really be wondering why their listbox didn't show any checkmarks, or why the setting they called didn't show in the UI. I don't think they'd just leave it at that and ship and wait until they had random crashes after deployment.

Similarly, a programmer who used your template code is going to wonder the same darn thing. "Why isn't my list box drawing checkboxes? I cast it to CCheckListBox!"  Calling any members on the object you get a pointer to from your template is going to do no good; the code that adds value is going to be killed as soon as it goes out of scope.

..B ekiM
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
Good point Mike.

If you are using one of the classes that add functionality (like CCheckListBox), then you'll be subclassing anyway (probably DDX_Control becuase it is the simplest way to do it) and won't need to call GetDlgItem anyway .. just use the CCheckListBox object you already have.

But one cannot comment aoubt some other user-defined CWnd-derived class that may have some data members or virtual functions in it that may NOT be directly related to what the user sees.

Lets cook up an example (to quote someone else :-)...

Say we derive a set of classes from CEdit that let you set the window text but first do some procesing on it (maybe translate to another language).

We'd have

class CMultiLingualEdit : public CEdit {
public:
  virutal void SetTextAndTransalte(CString s);
};

class CGermanEdit : public
public:
CMultiLingalEdit {
  virutal void SetTextAndTransalte(CString s);
};

now if one does

CGermanEdit* p = (CGermanEdit*)GetDlgItem(IDC_MYEDIT);
p->SetTextAndTranslate("hello");

then one would be in big trouble, because there would be no vtable entry for the SetTextAndTranslate function in the temporary CWnd object returned.

0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
Also Mike:

If the bad-cast-of-GetDlgItem symptom happened immediately, then one mightn't even see the dialog to see that it had checkboxes or not.  The app could well mysteriously fall down about ones virtual ears.  This would be during development, and so isn't appropriate for the joakimf case.

Of course, one would hope that the developer wouldn't ship an app that crashed like that ... microsoft certainly wouldn't :-) [only joking]
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
>class CGermanEdit : public
>public:
>CMultiLingalEdit {
>  virutal void SetTextAndTransalte(CString s);
>};

Of course, if you wrote it like I just did, you'd be in even more trouble.

meant to be:

class CGermanEdit : public CMultiLingalEdit {
public:
  virutal void SetTextAndTransalte(CString s);
};

Damn this narrow text-entry box.

0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility

 RONSLOW> then one would be in big trouble, because there would be no vtable
 RONSLOW> entry for the SetTextAndTranslate function in the temporary CWnd object returned.

They _might_ be in big trouble; there's only trouble if the item wasn't previously subclassed and/or attached.

..B ekiM
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
Exactly .. that is the situation that was being talked about(I thought) .. when there was not object anyway.  And the example of yours that I was commenting on was also when there was no subclassed/attached object (the CCheckListBox business).

It has already been WELL established from the beginning of all this that there is NO problem if the control is already subclassed/attached.

Anyway, why would you use GetDlgItem if you already have the actualy object anyway (eg. the CCheckListBox object)?

But, in the case we are discussing, there WOULD be a problem if you called a virtual member of a CWnd-derived class from a pointer cast from the return from GetDlgItem WHEN THERE IS NO CWND-DERIVED OBJECT ALLREADY ATTACHED TO THE CORRESPONDING CONTROL.

Phew.
0
 
LVL 1

Author Comment

by:joakimf
Comment Utility
Adjusted points to 200
0
 
LVL 1

Author Comment

by:joakimf
Comment Utility
Many good points here, first of all, this isn't panicing, I am just trying to find a reason why my app would crash. I can't debug it myself since it works 100% on my computers, therefore I feel like I am facing a big problem. And since this problem have been reported by less than 1% of the users, it's not easy to find any problem that way, since they don't give me any feedback on the problem. The only things that they have incomment is that Norton Crashguard is running. And when I read that the sample RONSLOW made only crashed when BoundsChecker was running, then perhaps the same thing with crashguard.

Now, I use the GetDlgItem casting on many different controls. CEdit, CButton, CListBox, CComboBox, CStatic. I Used it on CListCtrl before, but that didn't work so well, so I changed that control to DDX, and now that works fine.

The current version of the program is a complete rewrite from a month back. In the previous versions I used DDX. Using those versions with CrashGuard has not been any problems. It is in the new version I used GetDlgItem instead, the problems came up. Ofcourse there are other changes to the program, other than just the GetDlgItem. I think that I will change it to DDX again and see if that solves the problem. If not, then I will know that.

Any further comments on this, or else I will accept a comment as an answer.
0
 
LVL 1

Author Comment

by:joakimf
Comment Utility
Read a comment from "mikeblas":

Why doesn't anybody debug anymore?

Let me ask you this. How is it possible to debug an application that works on the computers you use to develop on? If you can answer that it would be great, I think that many programmers would be very happy.

I have debugged my program many times, to check for memory leaks and so on, but to find a problem that I can't recreate, well....
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
Have you tried it with CrashGuard on your development PC?  Or maybe with BoundsChecker?

Also, does it come up with an address for the crash without your program in the scrash message?

If so, there is a shareware tool called Exception Wizard that takes the .map file and .cod files (you have to tell VC to generate them) and from this takes you from the crash address to the source code line where the error occurred.  I've found this invaluable a number of times recently.  NOTE: that generating the map and cod files (large) do not effect the release exe (doesn't affect code size or performance).  Just make sure you've got a good few megabytes spare.

Get it here...

http://members.aol.com/~exceptwiz/index.html

Good luck!!

oh .. another product that could be useful is Mutek BugTrapper which can also tell you where errors occurred and show you all your function calls etc (think it requires the pdb file).  You can probably download a trial version from the Mutek site.

0
 
LVL 1

Author Comment

by:joakimf
Comment Utility
The errormessage says:

"MyFile.exe caused an invalid page fault in User32.dll"

So perhaps I can use some of the above named programs.
0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
> If you can answer that it would be great, I think that
 > many programmers would be very happy.

Sure.

First, try using Dr. Watson.

Then, try carefully replicating the client's environment on a machine of your own. At Microsoft, we spend tens of millions of dollars on that. But, you don't need to: just ask the customer about their machine and use their description to zone-in on it.

..B ekiM
0
 
LVL 1

Author Comment

by:joakimf
Comment Utility
I am always trying to recreate the enviroment that can cause the problem. But there is a problem that is called money. There are some difference between working in a large company and by develop the program as a person. Unfortunately am I unable to purchase all programs needed to check for every bug, therefore am I asking the above question, to see if there could be any connection between the CrashGuard problem and GetDlgItem casting.

I will try Dr. Watson as you suggested, and see if anything comes up with that. Never used it though, so this should be a first.

Anybody know a good book in debugging programs? Perhaps I need to learn more ways to dubug, than using just the built in debugger in Dev studio.
0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
> Anybody know a good book in debugging programs?

I've written several magazine articles on the subject.

But I haven't written any books on it, yet.  That takes too long, and pays too little.

..B ekiM
0
 
LVL 1

Author Comment

by:joakimf
Comment Utility
I accepted this as an answer since I thought that this thread was beginning to drift of the question asked. I think RONSLOW have helped me the most, I probably will change it to DDX, will it help? We'll see I guess. The other option is to use RONSLOWS template, but since I'm not very good with working with templates, that will be the last way out. Hope that I don't loose to much performance by using DDX_Control instead of GetDlgItem. I will also learn more debugging, thanks to mikeblas comments, and he should know what he's talking about. Therefore, have I posted a question to Mike so that you get atleast 100 points for your help.

I am in no way an expert MFC programmer, which perhaps shows by the problems I am having, but I am willing to learn...

Thanks for your comments....
0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
> I probably will change it to DDX

I really think you need to do more analysis before you run around making changes.

..B ekiM
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
MIKE:
re: analysis

Well .. if the change back to DDX_Control is simple then it is well worthwhile.

If the problem goes away, then it is possible that is what the problem was.  Either way, the problem has gone.

If the change is made and the problem remains, we know that it WASN'T the GetDlgItem calls at fault.

Elimination certainly make subsequent analysis easier .. less unknowns.

Regarding DDX_Control performance...

BTW: DDX_Control is probably MORE efficient than calling GetDlgItem all the time.

GetDlgItem has to not only call the SDK ::GetDlgItem to find the handle for the id, but also look up the permanent message map to see if there is a CWnd-Derived object, and lookup the temporary message map to see if there is a CTempWnd temporary object, and if neither is true, create a temporary window object and add it to the temporary table.  And then, when idle, MFC goes through the temporary table and deletes the temporary objects again.  IE. CWnd::GetDlgItem is not a cheap call to make.

With DDX_Control you do that work ONCE and then refer directly to the correct object in your code and bypasses all of the code above.  Much quicker.
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
It may well be worth getting Exception Wizard (it will help you convert from the cryptic DrWatcon output to something you can use).

Also BOundsChecker and BugTrapper are worthwhile products.  I am pretty sure you can get evaluation versions .. sound like your problem is a good one to evaluate!!

Roger
0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
RONSLOW> With DDX_Control you do that work ONCE and then refer directly to
 RONSLOW> the correct object in your code and bypasses all of the code above.  Much quicker.

You forgot to add-up and compare the work that DDX_Control does.

Since the control is now subclassed, MFC has to try and sink _every_ message sent to the control. That's quite expensive, and lasts for the duration of the window--whether you'll handle messages for that control, or not.

..B ekiM
0
 
LVL 1

Author Comment

by:joakimf
Comment Utility
Do I loose performance by using DDX_Control then? I mostely use CheckBoxes and when I use GetDlgItem casting it is to set or get the checkstate. Ofcourse I use other classes, but there are a lot of Checkboxes.
0
 
LVL 10

Expert Comment

by:RONSLOW
Comment Utility
I'd say, unless you are trying to drain every ounce of performance from your app .. then you probably won't notice the difference much anyway.

Applications (especially dialogs) spend most of their time waiting for user input anyway.

Also the difference between DDX_Control and dynamically creating window objects depends on what work your code does, what sort of controls you have, how many messages get sent, etc etc.

The only real way to tell (unless you do a LOT of analysis and have a deep and thorough knowledge of both MFC and windows processing internals) is to try it and see.

If there is not a noticable and required difference in performance .. go for what is the easiest to write, understand and maintain. A well written, eay to undersatand and maintain program is usually worth more that a few millseconds of performance.  Depends on whose time is worth the most.

Personally, I like the simplicity of DDX_Control .. it is a more declarative approach and (as there is less code to write) less susceptible to errors.  Those who come from a long background in direct API programming (especially in C) will prefer the familiar GetDlgItem approach (because it is what they are used to and understand more readily).  A lot of it is a question of personal taste.  As long as you are aware of the potential problems, tricks, performance differences etc.

My latest template class that encapsulates GetDlgItem etc is written so you can use it not only in individual functions for a local pointer to the control, but can also use them as memeber variables of the class .. so basically you declare the member, associate it with the id in the constructor, and then just use the variable .. no DDX_Control calls or need for DoDataExchange etc.  Using them this was still has the message processing the Mike refers to, but it gives you a consitent method of accessing controls through either memeber or local variables.  I'll put the latest version up here somewhere (or a link to it) when it is documented (and if I get time from doing paid work).
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Suggested Solutions

Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

743 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

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now