jjacksn
asked on
URGENT: Linking resolution problem
I'm having a problem with Unresolved Symbols.
I'm trying to integrate the source code found here:
http://support.microsoft.com/?kbid=171907
into a MAPI project. I'm having errors when it tries to reference the variables:
OutlookCOM error LNK2001: unresolved external symbol _CLSID_MailMessage
OutlookCOM error LNK2001: unresolved external symbol _IID_IMessage
Where CLSID_MailMessage is defined in that source code as
DEFINE_GUID(CLSID_MailMess age,
0x00020D0B,
0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);
in mapiguid.h there is the code
#if !defined(INITGUID) || defined(USES_IID_IMessage)
DEFINE_OLEGUID(IID_IMessag e, 0x00020307, 0, 0);
Both of the macros DEFINE_GUID and DEFINE_OLEGUID are called at the tope of my .cpp source file These vars are then referenced inside a class method in the same .cpp file.
Any thoughts as to why I am having this error:
I'm trying to integrate the source code found here:
http://support.microsoft.com/?kbid=171907
into a MAPI project. I'm having errors when it tries to reference the variables:
OutlookCOM error LNK2001: unresolved external symbol _CLSID_MailMessage
OutlookCOM error LNK2001: unresolved external symbol _IID_IMessage
Where CLSID_MailMessage is defined in that source code as
DEFINE_GUID(CLSID_MailMess
0x00020D0B,
0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);
in mapiguid.h there is the code
#if !defined(INITGUID) || defined(USES_IID_IMessage)
DEFINE_OLEGUID(IID_IMessag
Both of the macros DEFINE_GUID and DEFINE_OLEGUID are called at the tope of my .cpp source file These vars are then referenced inside a class method in the same .cpp file.
Any thoughts as to why I am having this error:
ASKER
it is currently above the #include directive. here is the top of the source file:
#include "OutlookCOMHdr.h"
#include "ContactCreator.h"
#define INITGUID
#include <objbase.h>
#define USES_IID_IMessage
#include <mapix.h>
#include <mapitags.h>
#include <mapidefs.h>
#include <mapiutil.h>
#include <mapiguid.h>
#include <imessage.h>
// {00020D0B-0000-0000-C000-0 0000000004 6}
DEFINE_GUID(CLSID_MailMess age,
0x00020D0B,
0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);
#include "OutlookCOMHdr.h"
#include "ContactCreator.h"
#define INITGUID
#include <objbase.h>
#define USES_IID_IMessage
#include <mapix.h>
#include <mapitags.h>
#include <mapidefs.h>
#include <mapiutil.h>
#include <mapiguid.h>
#include <imessage.h>
// {00020D0B-0000-0000-C000-0
DEFINE_GUID(CLSID_MailMess
0x00020D0B,
0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);
Try removing the underscores before the 2 variables.
IE:
OutlookCOM error LNK2001: unresolved external symbol _CLSID_MailMessage -> Replace just with CLSID_MailMessage
OutlookCOM error LNK2001: unresolved external symbol _IID_IMessage -> Replace just with IID_Imessage
try that or define them as external variables.
IE:
OutlookCOM error LNK2001: unresolved external symbol _CLSID_MailMessage -> Replace just with CLSID_MailMessage
OutlookCOM error LNK2001: unresolved external symbol _IID_IMessage -> Replace just with IID_Imessage
try that or define them as external variables.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
I believe the solution is to include initguid.h at the very beginning.
--
ged325
--
That _ (underscore) is added by the compiler, it isn't the source of the problem.
--
ged325
--
That _ (underscore) is added by the compiler, it isn't the source of the problem.
>> I believe the solution is to include initguid.h at the very beginning.
That is wrong as in initguid.h there is an
#ifndef DEFINE_GUID
#error initguid: must include objbase.h first.
#endif
Try to skip
#define INITGUID
in the CPP file you posted above
Regards, Alex
That is wrong as in initguid.h there is an
#ifndef DEFINE_GUID
#error initguid: must include objbase.h first.
#endif
Try to skip
#define INITGUID
in the CPP file you posted above
Regards, Alex
itsmeandnobodyelse:
I don't see that all in the file.
I don't see that all in the file.
>> I don't see that all in the file.
Maybe a subject of change... I am working with VC6.
initguid.h :
/************************* ********** ********** ********** ********** ********** **\
* *
* initguid.h - Definitions for controlling GUID initialization *
* *
* OLE Version 2.0 *
* *
* Copyright 1992 - 1998 Microsoft Corp. All rights reserved. *
* *
\************************* ********** ********** ********** ********** ********** **/
Pretty old, maybe they changed it in a younger version.
However, the problem is NOT that the source didn't include header files BUT that the macro INITGUID has been explicitly defined before including any Windows headers. That turns the GUID variables to be defined as 'extern' ==> the linker misses the storage for these GUID variables.
So, in exactly one CPP file using DEFINE_GUID and DEFINE_OLEGUID macros the #define INITGUID preprocessor statement MUST NOT be defined in order to get a storage for these variables.
Regards, Alex
Maybe a subject of change... I am working with VC6.
initguid.h :
/*************************
* *
* initguid.h - Definitions for controlling GUID initialization *
* *
* OLE Version 2.0 *
* *
* Copyright 1992 - 1998 Microsoft Corp. All rights reserved. *
* *
\*************************
Pretty old, maybe they changed it in a younger version.
However, the problem is NOT that the source didn't include header files BUT that the macro INITGUID has been explicitly defined before including any Windows headers. That turns the GUID variables to be defined as 'extern' ==> the linker misses the storage for these GUID variables.
So, in exactly one CPP file using DEFINE_GUID and DEFINE_OLEGUID macros the #define INITGUID preprocessor statement MUST NOT be defined in order to get a storage for these variables.
Regards, Alex
You're right about the forced definition of INITGUID being bad. I see that part of his code in the other posts.
My initguid.h defines that and then includes the proper guiddef header which creates all the macros/etc.
I'm using VS6 to answer this Q as well, which is interesting. Oh yes, I'm using the PlatformSDK on this machine. It is a lot more cleaned up by using guiddef.h after INITGUID definition and doesn't have that warning.
My initguid.h defines that and then includes the proper guiddef header which creates all the macros/etc.
I'm using VS6 to answer this Q as well, which is interesting. Oh yes, I'm using the PlatformSDK on this machine. It is a lot more cleaned up by using guiddef.h after INITGUID definition and doesn't have that warning.
ASKER
Thanks people! I'm out of town until Sunday, but I'm pretty sure you all pointed out the correct error and I will give you all points when I can verify it is what you think it is.
I'm still kind of confused though: why would FAR matter when its in the same source/object file?
I'm still kind of confused though: why would FAR matter when its in the same source/object file?
>> I'm still kind of confused though: why would FAR matter
FAR is an obsolete macro that defaults to nothing. So, it doesn't matter.
What matters is the different definition of macro DEFINE_GUID that is either
EXTERN_C const GUID FAR name
where name is the argument of the macro OR
EXTERN_C const GUID name \
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
The second one is a definition, i. e. a storage is allocated, while the first one only is an 'extern' declaration, where no storage is allocated.
Regards, Alex
FAR is an obsolete macro that defaults to nothing. So, it doesn't matter.
What matters is the different definition of macro DEFINE_GUID that is either
EXTERN_C const GUID FAR name
where name is the argument of the macro OR
EXTERN_C const GUID name \
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
The second one is a definition, i. e. a storage is allocated, while the first one only is an 'extern' declaration, where no storage is allocated.
Regards, Alex
ASKER
I see that now. Thanks. Out of curiosity, why are these headers structured like this?
It's rather a C++ problem but a header file problem:
If you will use a global variable - as a GUID - in more than one module (cpp file), there is a problem. If you define the variable in all modules as
int variable = 0;
the Linker will complain because of duplicate names. And the prog wouldn't work also as you need the _SAME_ variable in all modules.
The way out is the C++ keyword extern. If you declare in module b.cpp
extern int variable;
the Compiler knows, that for this variable no storage must be allocated, because it has already been defined in another module - say a.cpp - like
int variable = 0;
So in one module it must be defined and in all others it must be declared as extern.
But, a new problem arises, if you would like to make both alternatives by including the same header file - say h.h - both in a.cpp and b.cpp.
Mostly the solution is made using macros similar to that we had seen above:
// h.h
#ifdef DEFINE_MY_VARIABLE
int variable = 0;
#else
extern int variable;
#endif
That will be used like this in a.cpp
#define DEFINE_MY_VARIABLE
#include <h.h>
and in b.cpp and all other modules that need access to 'variable'
#include <h.h>
not defining DEFINE_MY_VARIABLE before.
A similar technique had been used above: defining INITGUID before including system headers leads to a defining macro that makes an extern declaration and ommitting the #define INITGUID turns the macro DEFINE_GUID to make a definition.
Hope, that was clear enough
Regards, Alex
If you will use a global variable - as a GUID - in more than one module (cpp file), there is a problem. If you define the variable in all modules as
int variable = 0;
the Linker will complain because of duplicate names. And the prog wouldn't work also as you need the _SAME_ variable in all modules.
The way out is the C++ keyword extern. If you declare in module b.cpp
extern int variable;
the Compiler knows, that for this variable no storage must be allocated, because it has already been defined in another module - say a.cpp - like
int variable = 0;
So in one module it must be defined and in all others it must be declared as extern.
But, a new problem arises, if you would like to make both alternatives by including the same header file - say h.h - both in a.cpp and b.cpp.
Mostly the solution is made using macros similar to that we had seen above:
// h.h
#ifdef DEFINE_MY_VARIABLE
int variable = 0;
#else
extern int variable;
#endif
That will be used like this in a.cpp
#define DEFINE_MY_VARIABLE
#include <h.h>
and in b.cpp and all other modules that need access to 'variable'
#include <h.h>
not defining DEFINE_MY_VARIABLE before.
A similar technique had been used above: defining INITGUID before including system headers leads to a defining macro that makes an extern declaration and ommitting the #define INITGUID turns the macro DEFINE_GUID to make a definition.
Hope, that was clear enough
Regards, Alex
Yea, and the PlatformSDK cleans this up a bit by providing a header change -- initguid.h -- that does this special declaration for you. You don't have to switch though, just the reason I gave the confusing/contradicting info before.
ASKER
Just got around to trying to fix this,
#include "OutlookCOMHdr.h"
#include "ContactCreator.h"
//#define INITGUID
#include <objbase.h>
#define USES_IID_IMessage
#include <mapix.h>
#include <mapitags.h>
#include <mapidefs.h>
#include <mapiutil.h>
#include <mapiguid.h>
#include <imessage.h>
// {00020D0B-0000-0000-C000-0 0000000004 6}
DEFINE_GUID(CLSID_MailMess age,
0x00020D0B,
0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);
This is still giving me the linking error
#include "OutlookCOMHdr.h"
#include "ContactCreator.h"
//#define INITGUID
#include <objbase.h>
#define USES_IID_IMessage
#include <mapix.h>
#include <mapitags.h>
#include <mapidefs.h>
#include <mapiutil.h>
#include <mapiguid.h>
#include <imessage.h>
// {00020D0B-0000-0000-C000-0
DEFINE_GUID(CLSID_MailMess
0x00020D0B,
0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);
This is still giving me the linking error
ASKER
btw, no other files are using these vars.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
no, that was in my cpp file, moving now...
Well, ok if it is your .cpp file then do the order I did with the objbase and initguid headers.
Then have your GUID defs/etc code after that.
As long as that include only called once within a .cpp file somewhere in the project.
Then have your GUID defs/etc code after that.
As long as that include only called once within a .cpp file somewhere in the project.
ASKER
ARG -- found it. Initguid.h was called in a different header. I removed it and now my headers work fine.
#define USES_IID_IMessage
to one of the project .cpp files, before #include "mapiguid.h"