|
|
|
i am defining a bunch of exception classes from a dll that are supposed to be thrown from within the DLL code to the GUI which loaded the dll.
it seems that i'm having trouble with the STL std::string::c_str() function when releasing its string.
here is my code :
DLL Exceptions header :
<font color=blue>#ifdef</font> VCALCPARSER_EXPORTS
<font color=blue>#define</font> VCALCPARSER_API <font color=blue>__declspec</font>(<font color=blue>dllexport</font>)
#else
<font color=blue>#define</font> VCALCPARSER_API <font color=blue>__declspec</font>(<font color=blue>dllimport</font>)
<font color=blue>#endif</font>
<font color=blue>#include</font> <STRING> <font color=green>
<font color=blue>class</font> VCALCPARSER_API CVCalcParserException {
<font color=blue>protected</font>:
ExceptionNumbers m_enExceptionNumber;
std::string m_strExceptionMsg;
<font color=blue>long</font> m_iErrorPos;
CVCalcParserException(ExceptionNumbers enExceptionNumber,
<font color=blue>const</font> std::string& strExceptionMsg,
<font color=blue>int</font> iErrorPos);
<font color=blue>public</font>:
<font color=blue>virtual</font> ~CVCalcParserException();
ExceptionNumbers GetExceptionNumber();
std::string GetMessage();
<font color=blue>long</font> GetErrorPos();
};
<font color=blue>class</font> VCALCPARSER_API CSyntaxException : <font color=blue>public</font> CVCalcParserException {
<font color=blue>protected</font>:
CSyntaxException(ExceptionNumbers enExceptionNumber,
const</font> std::string& strExceptionMsg,
<font color=blue>int</font> iErrorPos);
<font color=blue>public</font>:
<font color=blue>virtual</font> ~CSyntaxException();
};
<font color=blue>class</font> VCALCPARSER_API CMathematicExpressionExpectedException : <font color=blue>public</font> CSyntaxException {
<font color=blue>public</font>:
CMathematicExpressionExpectedException(<font color=blue>int</font> iErrorPos);
~CMathematicExpressionExpectedException();
};
then, when an such an error occurs (Mathematic expression expected), i send this exception :
VALUES_TYPE CVCalcParser::Evaluate(<font color=blue>const</font> std::string& strSource)
<font color=blue>throw</font>(CVCalcParserException) {
<font color=blue>this</font>->ResetParserMembers(strSource);
<font color=blue>try</font> {
VALUES_TYPE valResult = <font color=blue>this</font>->Level_1();
<font color=green></font>
}
<font color=blue>catch</font> (CVCalcParserException) {
<font color=blue>throw</font>;
}
<font color=blue>catch</font> (...) {
<font color=blue>throw</font> CUnknownException(0);
}
}
VALUES_TYPE CVCalcParser::Level_1(<font color=blue>void</font>)
<font color=blue>throw</font>(CVCalcParserException) {
VALUES_TYPE valLeftOperand = <font color=blue>this</font>->Level_2();
<font color=green></font>
}
VALUES_TYPE CVCalcParser::Level_2(<font color=blue>void</font>)
<font color=blue>throw</font>(CVCalcParserException) {
VALUES_TYPE valLeftOperand = <font color=blue>this</font>->Level_3();
<font color=green></font>
}
VALUES_TYPE CVCalcParser::Level_3(<font color=blue>void</font>)
<font color=blue>throw</font>(CVCalcParserException) {
VALUES_TYPE valLeftOperand = <font color=blue>this</font>->Level_4();
<font color=green></font>
}
VALUES_TYPE CVCalcParser::Level_4(<font color=blue>void</font>)
<font color=blue>throw</font>(CVCalcParserException) {
VALUES_TYPE valLeftOperand = <font color=blue>this</font>->Level_5();
<font color=green></font>
}
VALUES_TYPE CVCalcParser::Level_5(<font color=blue>void</font>)
<font color=blue>throw</font>(CVCalcParserException) {
VALUES_TYPE valLeftOperand = <font color=blue>this</font>->Primary();
<font color=green></font>
}
VALUES_TYPE CVCalcParser::Primary(<font color=blue>void</font>)
<font color=blue>throw</font>(CVCalcParserException) {
<font color=blue>this</font>->GetToken();
<font color=blue>switch</font> (<font color=blue>this</font>->m_tokCurrentToken) {
<font color=blue>case</font> ...:
<font color=green></font>
<font color=blue>default</font>:
<font color=blue>throw</font> CMathematicExpressionExpectedException(<font color=blue>this</font>->m_iCurrentIndex);
}
}
and at last, i catch this exception thrown from the dll in my GUI MFC project :
<font color=blue>void</font> CVisualCalcDlg::OnCalculate() {
CString strSource, strDest;
m_peInput->GetWindowText(strSource);
<font color=green>
<font color=blue>try</font> {
VALUES_TYPE valResult = m_Parser.Evaluate((LPCTSTR)strSource);
<font color=green></font>
}
<font color=blue>catch</font> (CSyntaxException& ex) {
strDest.Format(<font color=gray>"Syntax error %d : %s"</font>, ex.GetExceptionNumber(), ex.GetMessage().<code>c_str()</code>);
m_peInput->SetSel(ex.GetErrorPos(), ex.GetErrorPos());
}
<font color=blue>catch</font> (...) {
strDest.Format(<font color=gray>"Unknown parser internal error"</font>);
}
<font color=green></font>
}
when i look at the call stack, i see that the destructor of the std::string object is call at that point (it didn't leave the scope yet), and sope other functions are called down, until i get a dark message, that seems to say that i have a pointer that's been invalidated.
when i put a breakpoint on the line which contains that c_str() call and watch the ex exception object, all his datas (exception description message, position and error code) are correctly set.
i'm really stuck about that, because that behavior weren't happening when the code that i moved in the DLL was in the same project as the GUI.
any hint anybody ?
|
|
|
|
|
Probably what's happening (not sure at all) is that the string is allocating dynamically memory for its internal purpose. Then, when firing the exception, it will be catched in your exe and upon calling the destructor of this string, it will try to delete this memory. Unfortunately, as it hasn't been allocated by the same module (by the dll and not by your exe) this will crash.
But this is difficult to understand because you don't know how it works internally. A thing is sure: when you allocate memory in a dll and try to delete it inside your exe, this will crash the program. That's why classes exported from a dll have a Destroy method (it is just a delete this).
But here, I don't know how it works when an exception is fired...
|
|
|
|
|
hum, so you suggest me to have a Destroy() function in each my classes exported by the DLL ?
anyway, this seems to be much complicated, so i ask you a favour : can i send you the sources by email ?
thank you very much.
|
|
|
|
|
v2.0 wrote: hum, so you suggest me to have a Destroy() function in each my classes exported by the DLL ?
No, sorry, you misunderstood what I was saying (I took that just as an example).
I'm still thinking hard about what's happening here. One thing is almost sure: the string allocates memory dynamically for its own purpose. Now, as it is a template, I think (but at this point, my brain give me headache ) that the memory will be freed by your application when destructor is called. But at this point, I'm not sure. But if this is the case, this is what is causing the crash.
Can you tell me at which point the program breaks (I know it will be in a specific file). So give me the file and the line number. I have VC2005 installed so chances are that the files will be different. Can you post some code around the crashing point ?
That will help me to check if I'm right or not.
Otherwise I'm thinking of a solution but I don't find one right now. I'll keep searching
|
|
|
|
|
one more thing.
instead of
catch (CSyntaxException& ex) {
strDest.Format("Syntax error %d : %s", ex.GetExceptionNumber(), ex.GetMessage().c_str());
m_peInput->SetSel(ex.GetErrorPos(), ex.GetErrorPos());
}
i also tried the following codes, unsuccelsfully (all resulting in the same runtime crash when calling c_str() ) :
catch (CSyntaxException& ex) {
CString strTmp = ex.GetMessage().<code>c_str()</code>;
strDest.Format("Syntax error %d : %s", ex.GetExceptionNumber(), strTmp);
m_peInput->SetSel(ex.GetErrorPos(), ex.GetErrorPos());
}
catch (CSyntaxException& ex) {
char* strTmp = new char[ex.GetMessage().size()+1];
strcpy(strTmp, ex.GetMessage().<code>c_str()</code>);
strDest.Format("Syntax error %d : %s", ex.GetExceptionNumber(), strTmp);
m_peInput->SetSel(ex.GetErrorPos(), ex.GetErrorPos());
}
|
|
|
|
|
And what happens if you don't do anything in the catch block ?
If I'm right, then it should crash also, even if you don't call c_str(). Otherwise, I don't know what's happening
|
|
|
|
|
i emailed you with the project sources.
tell me if there are any points that you don't understand
cheers
ps : i'm going home, don't mind if i don't answer immediately
|
|
|
|
|
Yep I can take a look but this week-end I'm away until tuesday.
And it would be nice if you explain me the steps to reproduce the behavior (otherwise I'll spend too much time searching how to fire the exception )
|
|
|
|
|
very easy to reproduce
compile, link, launch, then type enter key when the dialog box appears.
it should display an error message saying "Mathematic expression expected", but it crashes there.
|
|
|
|
|
Damn, Cedric, i'm so happy, simply changing the DLL project runtime library property to multithreaded DLL (/MD or /MDd for debud version) solved the problem...
well, thanks you very much, you were more than useful on this point.
and you have the chance to be the 1st one playing with VisualCalc 3.0 beta 1(at the condition that you rebuild it correctly ).
hope to be able to update the article soon...
humm, well, so have a nice easter week-end dear
-- modified at 14:41 Saturday 15th April, 2006
|
|
|
|
|
Cool !
I'm glad it helped
BTW, I didn't receive your source code, that's strange.
Happy Easter for you too
|
|
|
|
|
Maybe a possible solution. I found that looking on the net (on this page[^])
Does getFileName() comes from a DLL? If so, make sure that your EXE and the<br />
DLL are both compiled with /MD (/MDd in debug builds) so you're both using<br />
the DLL version of the runtime. If you don't do that, you can't pass<br />
std::strings (or many other things) between the DLL and the EXE (or two<br />
DLLs, whatever the case may be).
Hope this will help
|
|
|
|
|
both DLL and exe projects are compiled in debug mode ('cause in the same solution).
|
|
|
|
|
Yep, but go in the properties of your project and go to the code generation tab. There you will have a selection for Runtime Mibrary. Check if this is well Multi-threaded DLL (I don't know exactly how it will affect your code) for both projects. There is also some valuable info in the thread I gave you (and I think I was at least partially right )
|
|
|
|
|
I found another interesting link[^]
I think this is more or less the problem you have.
|
|
|
|
|
A general rule of thumb is that it is not safe to throw an exception across a DLL boundary. Like most rules of thumb if you really know what you're doing you may be able to isolate specific cases in which it if safe to ignore it but in general the rule is sound.
Steve
|
|
|
|
|
Why is VC++ the best language to write an Office COM addin? I mean, why not VB, VBA, java or .NET?
---
With best regards,
A Manchester United Fan
The Genius of a true fool is that he can mess up a foolproof plan!
|
|
|
|
|
COM is a microsoft technology, so first, forget java.
VBA is VB for office applications (word, excel, etc), so forget it too.
for managed languages, they simply cannot generate native code...
|
|
|
|
|
v2.0 wrote: VBA is VB for office applications (word, excel, etc),
I do want to create an Office Add-in.
v2.0 wrote: for managed languages, they simply cannot generate native code...
I believe the JIT Compiler of the .NET framework compiles IL to Native code.
Could you give me some good solid reasons?
---
With best regards,
A Manchester United Fan
The Genius of a true fool is that he can mess up a foolproof plan!
|
|
|
|
|
LazyKancha wrote: Why is VC++ the best language to write an Office COM addin?
Being the "best" is mostly just a matter of opinion.
"Let us be thankful for the fools. But for them the rest of us could not succeed." - Mark Twain
"There is no death, only a change of worlds." - Native American Proverb
|
|
|
|
|
Hello , I copied a sample from msdn, but the compailer doesn't understend most of the language wordes ,The sample itself not importent for now,Only the compailer problem.
the semple is:
using namespace System;
int main()
{
array<string^>^args = Environment::GetCommandLineArgs();
const double tipRate = 0.18;
double billTotal;
if ( args->Length != 2 )
{
Console::WriteLine( "usage: TIPCALC total" );
return 1;
}
else
{
try
{
billTotal = Double::Parse( args[ 1 ] );
}
catch ( FormatException^ )
{
Console::WriteLine( "usage: TIPCALC total" );
return 1;
}
double tip = billTotal * tipRate;
Console::WriteLine();
Console::WriteLine( "Bill total:\t{0,8:c}", billTotal );
Console::WriteLine( "Tip total/rate:\t{0,8:c} ({1:p1})", tip, tipRate );
Console::WriteLine( ((String^)"")->PadRight( 24, '-' ) );
Console::WriteLine( "Grand total:\t{0,8:c}", billTotal + tip );
return 0;
}
}
/////////////////////////////////////////////////////
and I get this answer from compiler:
/////////////////////////////////////////////
------ Build started: Project: testing_from_books, Configuration: Debug Win32 ------
Compiling...
general_uri.cpp
.\general_uri.cpp(2) : error C2871: 'System' : a namespace with this name does not exist
.\general_uri.cpp(5) : error C2065: 'array' : undeclared identifier
.\general_uri.cpp(5) : error C2065: 'String' : undeclared identifier
.\general_uri.cpp(5) : error C2059: syntax error : '>'
.\general_uri.cpp(5) : error C2653: 'Environment' : is not a class or namespace name
.\general_uri.cpp(8) : error C2065: 'args' : undeclared identifier
.\general_uri.cpp(8) : error C2227: left of '->Length' must point to class/struct/union/generic type
type is ''unknown-type''
.\general_uri.cpp(10) : error C2653: 'Console' : is not a class or namespace name
.\general_uri.cpp(10) : error C3861: 'WriteLine': identifier not found
.\general_uri.cpp(17) : error C2653: 'Double' : is not a class or namespace name
.\general_uri.cpp(17) : error C3861: 'Parse': identifier not found
.\general_uri.cpp(19) : error C2061: syntax error : identifier 'FormatException'
.\general_uri.cpp(19) : error C2310: catch handlers must specify one type
.\general_uri.cpp(21) : error C2653: 'Console' : is not a class or namespace name
.\general_uri.cpp(21) : error C3861: 'WriteLine': identifier not found
.\general_uri.cpp(25) : error C2317: 'try' block starting on line '16' has no catch handlers
.\general_uri.cpp(26) : error C2653: 'Console' : is not a class or namespace name
.\general_uri.cpp(26) : error C3861: 'WriteLine': identifier not found
.\general_uri.cpp(27) : error C2653: 'Console' : is not a class or namespace name
.\general_uri.cpp(27) : error C3861: 'WriteLine': identifier not found
.\general_uri.cpp(28) : error C2653: 'Console' : is not a class or namespace name
.\general_uri.cpp(28) : error C3861: 'WriteLine': identifier not found
.\general_uri.cpp(29) : error C2653: 'Console' : is not a class or namespace name
.\general_uri.cpp(29) : error C2059: syntax error : ')'
.\general_uri.cpp(30) : error C2653: 'Console' : is not a class or namespace name
.\general_uri.cpp(29) : error C3861: 'WriteLine': identifier not found
.\general_uri.cpp(30) : error C3861: 'WriteLine': identifier not found
Build log was saved at "file://f:\Documents and Settings\uri\My Documents\אורי\חומר ופרויקטים ב-C++\Visual Studio 2005\Projects\testing_from_books\testing_from_books\Debug\BuildLog.htm"
testing_from_books - 27 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
//////////////////////////////////////////////////////////////
Why
|
|
|
|
|
|
I want to learn some knowledge about OLE and "Inside OLE" is considered to be one of the most classical book about it.I search many website,but still can't find its electronic version.So if anyone have this ebook,I hope you can share it to me.Thanks a lot.
My Email: tombfifa2@hotmail.com
Best wishes!;)
-- modified at 4:34 Friday 14th April, 2006
|
|
|
|
|