Link to home
Start Free TrialLog in
Avatar of joakimf
joakimf

asked on

GetDlgItem() casting. RONSLOW.....

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()?
Avatar of Vinayak Kumbar
Vinayak Kumbar

Interesting.....

VinExpert
Avatar of joakimf

ASKER

Adjusted points to 100
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.
Avatar of joakimf

ASKER

Thanks for your comment <miguel>, but what you commented was exactly the same thing as <RONSLOW> and a couple of other experts discussed in:
https://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.
If it only crashes when Crashguard is running then it sounds like a problem with Crashguard. Has this been reported to Norton?
If it only crashes when Crashguard is running then it sounds like a problem with Crashguard. Has this been reported to Norton?
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
This is getting a bit ridiculous, its gone from an interesting technical discussion to mass-panic.
This is getting a bit ridiculous, its gone from an interesting technical discussion to mass-panic.
ASKER CERTIFIED SOLUTION
Avatar of RONSLOW
RONSLOW

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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
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.

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]
>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.


 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
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.
Avatar of joakimf

ASKER

Adjusted points to 200
Avatar of joakimf

ASKER

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.
Avatar of joakimf

ASKER

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....
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.

Avatar of joakimf

ASKER

The errormessage says:

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

So perhaps I can use some of the above named programs.
> 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
Avatar of joakimf

ASKER

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.
> 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
Avatar of joakimf

ASKER

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....
> I probably will change it to DDX

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

..B ekiM
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.
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
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
Avatar of joakimf

ASKER

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.
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).