Link to home
Start Free TrialLog in
Avatar of jjacksn
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_MailMessage,
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_IMessage,          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:
Avatar of AlexFM
AlexFM

Try to add line

#define USES_IID_IMessage

to one of the project .cpp files, before #include "mapiguid.h"
Avatar of jjacksn

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-000000000046}
DEFINE_GUID(CLSID_MailMessage,
0x00020D0B,
0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);
Avatar of Kyle Abrahams, PMP
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.

ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

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

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

itsmeandnobodyelse:

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

Avatar of jjacksn

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

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
   
Avatar of jjacksn

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

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-000000000046}
DEFINE_GUID(CLSID_MailMessage,
0x00020D0B,
0x0000, 0x0000, 0xC0, 0x00, 0x0, 0x00, 0x0, 0x00, 0x00, 0x46);

This is still giving me the linking error  
Avatar of jjacksn

ASKER

btw, no other files are using these vars.
SOLUTION
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
Avatar of jjacksn

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

ASKER

ARG -- found it.  Initguid.h was called in a different header.  I removed it and now my headers work fine.