Hello everyone.
I have a question that will probably expose me as the newbie that I am, but hey!, everybody is at some point in time. :)
My scenario:
I mainly use C++ to develop COM. Although I have read extensively on how to program it from scratch (Don Box has written an excellent book about the subject), I usually use ATL to reduce the development time.
So I read about ISupportErrorInfo. I need to implement it so my clients can reliably read the user-defined error description I want to set. But let's be honest: It is a real pain to post error information in COM every time you need to return your error HRESULT. For the sake of clarity, I'll enumerate the steps:
1. Call CreateInfoError() to obtain a ISetErrorInfo pointer to an error object.
2. Using the error object:
-Set the interface GUID.
-Set the error description.
-Set the source name. Microsoft states that the source should be the object's name or the application name. I am deriving the object name from its CLSID by means of ProgIDFromCLSID().
3. Call SetErrorInfo() to assign the error object to the current thread.
So all that goes into almost every single one of the following IF statements:
1 2 3 4 5
|
if (FAILED(hr))
{
....
return MAKE_HRESULT(...)
}
|
No way! So I started by defining a function with the following signature
1 2 3 4
|
HRESULT RaiseCOMError(REFIID riid, REFCLSID source, USHORT errCode, LPOLESTR szDescription = NULL)
{
...
}
|
Good. Then I did some generic macros that simplify a little bit my calling of this function.
Microsoft states that user-defined errors are declared per-interface. I have 2 objects. I therefore created 2 header files that define each the error codes for 2 different dual interfaces. I added one macro each that further simplifies the calling of RaiseCOMError() by hardcoding the IID into it.
Now I went to my classes' header files and included both the generic header file that defines RaiseCOMError() as well as the header file that defines the errors for the implemented interface, and further defined a macro that calls RaiseCOMError using the object's CLSID. At this point I only need to pass the name of the error code and I'm good to go. I was really proud of myself.
To be honest with you, I did all this for one of my classes only. After I debugged and polished, I added this stuff for my second class. After I did this, I cannot compile because the function RaiseCOMError() is being multiply defined.
How come ATL is all in headers and I cannot do that!!?? What am I missing?
The header file that contains RaiseCOMError() (called UserDefinedErrors.h) has #pragma once as well as compilation guards. The same goes for my ATL-generated header files for the classes I use, and the same goes for the header files that define the error codes for the interfaces.
Your help is appreciated.
BTW, I can probably correct the problem by creating a UserDefinedErrors.cpp file that defines RaiseCOMErrors() and then use the UserDefinedErrors.h file to declare the function using the extern keyword. But this approach bothers me because I wanted to have my header file in a common folder where I can link to it whenever I needed it. Now I need to copy a CPP file too? Sounds like I can do better, I just don't know how to do better. :D
I'll shut up now. Thanks in advance!