|
|
Good afternoon to all,
I have been having this fight with my code since early this morning and I am running short on ideas....real short.
Lets start with the characteristics of the issue.
-On my development station everything is fine. The app is complete and ready to ship actually, once this is resolved.
-On the client station the app becomes unresponsive.
-Since there is nothing...not even a single exception thrown during debugging, I ended up posting MessageBox messages throughout the application to nail down exactly where the problem happens.
-I nailed it down to this. The application uses a DLL that I built. The DLL holds one class. The class is a CFileTemplate that takes a XML file reads it and returns an array. The xml file being a template file for columnsId, field names, data type, and length .....to read a CVS or Excel file.
-------------------------
Ok...lets describe the behavior now. When the application runs the user clicks a button to open an OpenFileDialog object, which returns the path to the template file. When it does so the application creates an instance of my CFileTemplate class. When I do this on the client station the application becomes unresponsive when I click the button to get the file dialog. If I put the instantiation in another method and call that method instead of the instantiation directly, I will see the dialog and use the Ok...and then the application becomes unresponsive.
Basically the method that holds the instantiation becomes unresponsive. Not executed at all!!!
If I comment out the instantiation of the class the method that holds the instantiation runs fine...and the application keeps working....as long as I don't use anything that requires that template file of course. So I assumed the problem was within my DLL
Still I don't understand why it is the method that holds the creation of my object that becomes unresponsive. It should at least run in the method as far as the instantiation, but no....if there is a compiled instantiation line in the method. The whole method is not executed. The call appears in the call stack, but nothing in the methods is executed.
None the less I looked at my DLL and changed the way the constructor works, by leaving variables initialization in there and use an Init() method to start working....basically read the xml file and assimilate its data. Then I put messageboxes in there to see what would happen. Of course on my development machine I see everything...all the messages....everything is executed and I see no problem.
On the client machine though, if I instantiate the object, the whole method that holds the instantiation is skipped and the app becomes unresponsive. Therefore my ctor is never called....therefore I do not get to see any of my messages.....hence I don't know what is going wrong.
This whole behavior and non stepping in the method is driving me out of my mind. The whole behavior beats me.....Instantiation of a class, even flawed class, wouldn't affect execution of the instructions that come before it. Why would the whole method that holds the instantiation become unresponsive????
Does this kind of behavior means anything to anyone? Is there anything I can do to figure out what is going? If you want snippets, ask and I'll post. I am even ready to send some code if required, because this is mind blowing. I have been thinking about my first article on here for a while. I guess I just found a good idea, once I figure this out.
Edit: Everything .Net 2.0. All stations, dev and clients, are WinXP SP2. The DLL only has .Net dependencies, mainly System, System.Xml, System.Windows.Forms
Dewm Solo - Managed C++ Developer
|
|
|
|
|
Hi,
some ideas:
1.
is there any static code in your class? i.e. code that needs to execute as soon as the class
gets loaded (because somewhere else a method gets JIT-compiled that will eventually need something
from your class). Your static class code may either take a long time to complete,
or fail all together,
even before you actually ask it to do something for you. Inserting one more method may alleviate
(or just delay) the problem, since the new method will be looked up but not yet JIT-compiled
until it is needed for execution.
2.
exceptions that occur in a constructor or in another thread may go unnoticed, unless you
implement a try-catch construct in the constructor; of course in the catch you should output
as much information as possible, at least Exception.ToString().
3.
I guess 2 also holds true for any static code in a class.
modified on Friday, December 14, 2007 4:49:28 PM
|
|
|
|
|
1. This class does 3 things.
-Instantiate itself by saving the path for the file
-Read through the file and assimilate the template
-Return the template array
I didn't want to have to call the reading part. I wanted to initialize and return the template when asked. So the ReturnTemplate() method is public, but the ReadFile() method is private. ReadFile() is called in the ctor as you said. For test purposes I will make it public and call it from my application after initialization of the class. If it does initialize at that point.
2 & 3. When trying to figure out what was going on I did insert try-catch constructs everywhere. In the calling method, in the ctor, in the ReadFile() method, ......everwhere....nothing gets intercepted...nothing, nothing, nothing.
I will go change the ctor and make that read method public right now. I will post back my findings within the next minutes.
Dewm Solo - Managed C++ Developer
|
|
|
|
|
Well I'm almost beat....I changed the way it works like I said I would. So now the ctor does nothing but save that path until the read method is called.
Yet instantiating this class still makes the application stop responding. Just as a reminder....only on client stations. On a dev station no problem.
Class Declaration:
<br />
typedef cli::array< cli::array<string^>^ > TemplateArray;<br />
<br />
public ref class CFileTemplate{<br />
public:<br />
CFileTemplate(String^ sPath);<br />
~CFileTemplate();<br />
<br />
private:<br />
String^ m_FilePath;<br />
TemplateArray^ arrCurrentTemplate;<br />
public:<br />
<br />
public:
void Process();<br />
public:<br />
void SwitchTemplate(String^ sPath);<br />
TemplateArray^ ReturnFormat();<br />
<br />
<br />
};<br />
</string^>
The class' ctor:
<br />
CFileTemplate::CFileTemplate(String^ sPath) : m_FilePath(sPath)<br />
{<br />
MessageBox::Show("ctor");<br />
}<br />
In the main application, here is the call:
<br />
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {<br />
String^ myStream;<br />
<br />
MessageBox::Show("Opening dialog");<br />
if ( this->openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK )<br />
{<br />
MessageBox::Show("Making sure the stream is not empty");<br />
if ( (myStream = this->openFileDialog1->FileName) != nullptr )<br />
{<br />
MessageBox::Show("Instiating the file template object");<br />
this->aTemplate = gcnew MFG::CFileTemplate(myStream->ToString());
MessageBox::Show("instance created");<br />
}<br />
}<br />
}<br />
Ok....to complete the explanation.....like this I never get to see the file dialog....nothing gets executed in the click event.
BUT!!!!!!!!!!
If I comment the line that instantiates the class.....everything goes fine. Except I cannot call the read method of course...the thing isn't instantiated.
Dewm Solo - Managed C++ Developer
|
|
|
|
|
Hi,
I'm not fluent in C++ (doing almost everything in C#) so I may miss the obvious.
I see no static code in your class, except for the fact that it refers to a generic array,
for which it needs to assemble the code. So I would suggest you try again without the line
TemplateArray^ arrCurrentTemplate; , it is my guess that line (or more likely the
typedef it uses) is the culpritt somehow.
|
|
|
|
|
Removed it and compensated with the appropriate array.....
Still...same problem!!!!
Dewm Solo - Managed C++ Developer
|
|
|
|
|
OK,
in the mean time I'm puzzled by the line CFileTemplate::CFileTemplate(String^ sPath) : m_FilePath(sPath)
which seems to indicate inheritance although the class declaration itself did not have any.
Anyway m_FilePath is not a type, it is a member
|
|
|
|
|
Luc Pattyn wrote: I'm puzzled by the line CFileTemplate::CFileTemplate(String^ sPath) : m_FilePath(sPath)
Hi Luc!
After the colon is the initializer list
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Hi Mark,
thanks for reminding me. I knew once, but forgot again.
Anyway the OP is in good hands now.
|
|
|
|
|
Heh. The OP was already in good hands.
I just can't resist tossing my 2 cents in
Cheers!
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I'm sure, at least in C++, and probably in more areas, your 2 cents carry more weight than mine...
|
|
|
|
|
I'm not seeing anything here.
A couple notes...
Dewm Solo wrote: if ( (myStream = this->openFileDialog1->FileName) != nullptr )
openFileDialog1->FileName should be compared to String::Empty - the default value, not nullptr.
Dewm Solo wrote: myStream->ToString()
Why?
When the app goes unresponsive, if you break in the debugger, where's
the current execution point at?
Mark
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark Salsbery wrote: openFileDialog1->FileName should be compared to String::Empty - the default value, not nullptr.
Took note of that. Thanks
Mark Salsbery wrote: Why?
....Well just to make it obvious that it really does comes out as a String...It would get optimized anyways wouldn't it?
Mark Salsbery wrote:
When the app goes unresponsive, if you break in the debugger, where's
the current execution point at?
If I could have done that, believe me I would have. Like I said this issue only appears on non-development workstations. On my dev station everything works fine. No hangs or nothing. Before shipping to customers, I do like to test on regular stations that we have at work. So I tried two different machines and both did have the issue we are trying to solve now.
Dewm Solo - Managed C++ Developer
|
|
|
|
|
Hi Dewm,
You were getting your money's worth from Luc and Mark - here's my penny. I'll take the change with no insults...
1) Look at the generated IL. Richter does this extensively in his book CLR via C#[^]. Veryify the IL generated is what you wanted.
2) Change from initialization to assignment. I would expect if this is an issue, it is unveiled in (1).
3) WinDbg with SOS. WinDbg can debug IL. I've never had to do it, but John Robbins covers the topic extensively in Debugging Applications for Microsoft® .NET and Microsoft Windows®[^].
Jeff
|
|
|
|
|
|
Ok....I think I'm losing it guys.
I added a testclass like this:
<br />
public ref class TestClass {<br />
public: <br />
TestClass(String^ jj);<br />
~TestClass();<br />
<br />
private:<br />
String^ sPath;<br />
};<br />
With implementation like this:
<br />
TestClass::TestClass(String^ jj)<br />
{<br />
}<br />
<br />
TestClass::~TestClass()<br />
{<br />
}<br />
How much more simple can it get?
Instantiating it like this:
<br />
private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) {<br />
MFG::TestClass^ ttt = gcnew MFG::TestClass("test");<br />
MessageBox::Show("instance created");<br />
}<br />
Works fine on my dev station of course, but it hangs on two other stations here that are non dev.
Dewm Solo - Managed C++ Developer
|
|
|
|
|
Creation of such a testclass in my project of course works 100% on any workstation.
So now I'm going to create a new DLL with just a test class.
Dewm Solo - Managed C++ Developer
|
|
|
|
|
Ok,....Referencing a test DLL with just a test class does the same at instantiation.
The next thing I'm thinking of trying is a test app that will reference this new test dll and see what happens.
Dewm Solo - Managed C++ Developer
|
|
|
|
|
I creating a windows form application. I Referenced that test dll. In a button's click event created an instance of the test class.
Nothing can go wrong right? I have done this at least a million times. Well ...same problem on the workstation. Does anyone has an idea? There are no other dependencies. There is nothing that can cause such a hang.
...hmmm...Just thought of something. I'm going to try to run a release build. I don't expect much out of this, but who knows what compiler optimizations might come up with.
I tried this and the release builds does exactly the same. An empty app with just a button and reference to a dll that contains only a test class that has a ctor, dtor, and one string member only. It still hangs at creation of a test class object. Does anyone has suggestions? At this point I am wondering if this is not a problem that has to do with the .Net installation on the client station. Although this happens on more than one client station....
How can I debug this? On a client station nonetheless.
Dewm Solo - Managed C++ Developer
modified on Tuesday, December 18, 2007 2:53:56 PM
|
|
|
|
|
Hi, I'm using Visual Studio 2005 C++/CLI. I have overridden the OnPaint() method. If I draw something on the form due to a button click and then Invalidate() is invoked the OnPaint() method then draws the Form1 over thus erasing what I just drew. My work around for this is to define a set of booleans (one for each object) and then check the values of the booleans in the OnPaint() method to see if they need to be repainted. Is there a better way to do this?
Buck
|
|
|
|
|
Handle WM_ERASEBKGND as well, and don't ever call the base class. You wil need to draw the whole form yourself then.
Christian Graus - Microsoft MVP - C++
"also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
|
|
|
|
Hi, I'm using visual Studio 2005 C++/CLI. I need to have some Graphics^ shapes on a display and I want them to have NO FILL so they will appear transparent. The System::Drawing::Color does not have a Color::None or Color::Clear. This is probably pretty simple but I can't seem to find the answer.
Buck
|
|
|
|
|
The color is transparent.
|
|
|
|
|
System::Drawing::Color::Transparent ?
*EDIT* Oops I see you knew that
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|