Is forward declaration of ATL autogenerated _com_ptr_t possible?
-
In normal C++ when a class header only contains a reference or a pointer to a class it is better to not #include the definition but wait until the .cpp file to avoid coupling/avoid recompilation. In our of our class headers the reference concerned is to a smart pointer generated from a #import, in other words a smart pointer of the form _COM_SMARTPTR_TYPEDEF(IComInterface, &__uuidof(IComInterface)) Which expands to typedef _com_ptr_t<_com_IIID<icominterface,> > IComInterface; I think the problem is that the __declspec(uuid("GUID VALUE")) which is attached to the forward declaration of the IComInterface struct like __stdcall and __fastcall is part of the declaration and so will produce different types depending on the contents of uuid. The problem however is that the uuid contents will be autogenerated by the #import line, and so it won't be possible know ahead of time to know what to put in the typedef. I also think that the $(InputName)_i.c file generated when building the COM component won't help because although it contains the correct GUID it won't be in the correct form for __uuidof
-
In normal C++ when a class header only contains a reference or a pointer to a class it is better to not #include the definition but wait until the .cpp file to avoid coupling/avoid recompilation. In our of our class headers the reference concerned is to a smart pointer generated from a #import, in other words a smart pointer of the form _COM_SMARTPTR_TYPEDEF(IComInterface, &__uuidof(IComInterface)) Which expands to typedef _com_ptr_t<_com_IIID<icominterface,> > IComInterface; I think the problem is that the __declspec(uuid("GUID VALUE")) which is attached to the forward declaration of the IComInterface struct like __stdcall and __fastcall is part of the declaration and so will produce different types depending on the contents of uuid. The problem however is that the uuid contents will be autogenerated by the #import line, and so it won't be possible know ahead of time to know what to put in the typedef. I also think that the $(InputName)_i.c file generated when building the COM component won't help because although it contains the correct GUID it won't be in the correct form for __uuidof
Try declaring a variable that (in some .cpp file) you'll define & initialise to the IID of the interface, like this:
class ITest ;
extern const IID ITest_IID;
_COM_SMARTPTR_TYPEDEF(ITest, ITest_IID);That correctly forward declares ITestPtr so you can a) use a reference to it without needing the definition of
ITest
orITest_IID
, but b) can use the thing referred to onceITest
andITest_IID
have been defined.Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
Try declaring a variable that (in some .cpp file) you'll define & initialise to the IID of the interface, like this:
class ITest ;
extern const IID ITest_IID;
_COM_SMARTPTR_TYPEDEF(ITest, ITest_IID);That correctly forward declares ITestPtr so you can a) use a reference to it without needing the definition of
ITest
orITest_IID
, but b) can use the thing referred to onceITest
andITest_IID
have been defined.Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
I get the error "redefinition; different basic types" when the #import defines the real thing.
-
I get the error "redefinition; different basic types" when the #import defines the real thing.
You need to decouple things a bit more in that case. Here's an example that builds: In the .h file:
class ITest ;
extern const IID ITest_IID;
_COM_SMARTPTR_TYPEDEF(ITest, ITest_IID);In the .cpp file:
#import "libid:00020813-0000-0000-C000-000000000046" version("1.6") auto_search no_dual_interfaces rename("DialogBox", "excelDialogBox") rename("RGB", "excelRGB") rename("DocumentProperties", "excelDocumentProperties") rename("SearchPath", "excelSearchPath") rename("CopyFile", "excelCopyFile") rename("ReplaceText", "excelReplaceText")
class ITest : public Excel::_Application {};
const IID ITest_IID = __uuidof(Excel::_Application);This defines a smart pointer, ITestPtr that wraps an Excel _Application pointer.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
You need to decouple things a bit more in that case. Here's an example that builds: In the .h file:
class ITest ;
extern const IID ITest_IID;
_COM_SMARTPTR_TYPEDEF(ITest, ITest_IID);In the .cpp file:
#import "libid:00020813-0000-0000-C000-000000000046" version("1.6") auto_search no_dual_interfaces rename("DialogBox", "excelDialogBox") rename("RGB", "excelRGB") rename("DocumentProperties", "excelDocumentProperties") rename("SearchPath", "excelSearchPath") rename("CopyFile", "excelCopyFile") rename("ReplaceText", "excelReplaceText")
class ITest : public Excel::_Application {};
const IID ITest_IID = __uuidof(Excel::_Application);This defines a smart pointer, ITestPtr that wraps an Excel _Application pointer.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
It works up to a point, but the moment I introduce an accessor function to return a valid COM object the type ITest I get error C2027: use of undefined type 'ITest' So: HashImport.h
#pragma once
#include struct ITest;
extern const IID ITest_IID;
_COM_SMARTPTR_TYPEDEF(ITest, ITest_IID);class CHashImport
{
public:
CHashImport();
~CHashImport();
HRESULT GetImpl(ITestPtr &pImpl);
};HashImport.cpp
#include "StdAfx.h"
#include "Hashimport.h"#import "libid:00020813-0000-0000-C000-000000000046" version("1.6") auto_search no_dual_interfaces rename("DialogBox", "excelDialogBox") rename("RGB", "excelRGB") rename("DocumentProperties", "excelDocumentProperties") rename("SearchPath", "excelSearchPath") rename("CopyFile", "excelCopyFile") rename("ReplaceText", "excelReplaceText")
struct ITest : public Excel::_Application {};
using namespace Excel;
const IID ITest_IID = __uuidof(Excel::_Application);
CHashImport::CHashImport()
{
ITestPtr ptr;
GetImpl(ptr);
}CHashImport::~CHashImport()
{
}HRESULT CHashImport::GetImpl(ITestPtr &pImpl)
{
pImpl = ITestPtr(__uuidof(Excel::Application));
_bstr_t appname = pImpl->GetValue();
return S_OK;
}referenceheader.h
#pragma once
#include "hashimport.h"class CReferenceHeader
{
public:
CReferenceHeader();
~CReferenceHeader();
};referenceheader.cpp
#include "StdAfx.h"
#include "Referenceheader.h"CReferenceHeader::CReferenceHeader()
{
}CReferenceHeader::~CReferenceHeader()
{
}main.cpp
#include "stdafx.h"
#include "hashimport.h"
#import "libid:00020813-0000-0000-C000-000000000046" version("1.6") auto_search no_dual_interfaces rename("DialogBox", "excelDialogBox") rename("RGB", "excelRGB") rename("DocumentProperties", "excelDocumentProperties") rename("SearchPath", "excelSearchPath") rename("CopyFile", "excelCopyFile") rename("ReplaceText", "excelReplaceText")int _tmain(int argc, _TCHAR* argv[])
{
::CoInitialize(NULL);
CHashImport import;
//ITestPtr pTest; //error C2027: use of undefined type 'ITest'
//import.GetImpl(pTest);
//c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\comip.h(822) : error C2227: left of '->Release' must point to class/struct/union::CoUninitialize(); return 0;
}
-
It works up to a point, but the moment I introduce an accessor function to return a valid COM object the type ITest I get error C2027: use of undefined type 'ITest' So: HashImport.h
#pragma once
#include struct ITest;
extern const IID ITest_IID;
_COM_SMARTPTR_TYPEDEF(ITest, ITest_IID);class CHashImport
{
public:
CHashImport();
~CHashImport();
HRESULT GetImpl(ITestPtr &pImpl);
};HashImport.cpp
#include "StdAfx.h"
#include "Hashimport.h"#import "libid:00020813-0000-0000-C000-000000000046" version("1.6") auto_search no_dual_interfaces rename("DialogBox", "excelDialogBox") rename("RGB", "excelRGB") rename("DocumentProperties", "excelDocumentProperties") rename("SearchPath", "excelSearchPath") rename("CopyFile", "excelCopyFile") rename("ReplaceText", "excelReplaceText")
struct ITest : public Excel::_Application {};
using namespace Excel;
const IID ITest_IID = __uuidof(Excel::_Application);
CHashImport::CHashImport()
{
ITestPtr ptr;
GetImpl(ptr);
}CHashImport::~CHashImport()
{
}HRESULT CHashImport::GetImpl(ITestPtr &pImpl)
{
pImpl = ITestPtr(__uuidof(Excel::Application));
_bstr_t appname = pImpl->GetValue();
return S_OK;
}referenceheader.h
#pragma once
#include "hashimport.h"class CReferenceHeader
{
public:
CReferenceHeader();
~CReferenceHeader();
};referenceheader.cpp
#include "StdAfx.h"
#include "Referenceheader.h"CReferenceHeader::CReferenceHeader()
{
}CReferenceHeader::~CReferenceHeader()
{
}main.cpp
#include "stdafx.h"
#include "hashimport.h"
#import "libid:00020813-0000-0000-C000-000000000046" version("1.6") auto_search no_dual_interfaces rename("DialogBox", "excelDialogBox") rename("RGB", "excelRGB") rename("DocumentProperties", "excelDocumentProperties") rename("SearchPath", "excelSearchPath") rename("CopyFile", "excelCopyFile") rename("ReplaceText", "excelReplaceText")int _tmain(int argc, _TCHAR* argv[])
{
::CoInitialize(NULL);
CHashImport import;
//ITestPtr pTest; //error C2027: use of undefined type 'ITest'
//import.GetImpl(pTest);
//c:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\include\comip.h(822) : error C2227: left of '->Release' must point to class/struct/union::CoUninitialize(); return 0;
}
Yeah, that's because
main.cpp
needs a full definition of ITest or whatever the smart pointer class would be. You have no option at that point but to have a full definition of ITest. Rename HashImport.h to HashImportFwd.h (like you have ios and iosfwd in the standard library). Then create a new header called HashImport.h containing this:#include "HashimportFwd.h"
#import "libid:00020813-0000-0000-C000-000000000046" version("1.6") auto_search no_dual_interfaces rename("DialogBox", "excelDialogBox") rename("RGB", "excelRGB") rename("DocumentProperties", "excelDocumentProperties") rename("SearchPath", "excelSearchPath") rename("CopyFile", "excelCopyFile") rename("ReplaceText", "excelReplaceText")
struct ITest : public Excel::_Application {};
Now, use HashImportFwd.h where the forward declaration is all that's needed and HashImport.h where you need the full definition.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
Yeah, that's because
main.cpp
needs a full definition of ITest or whatever the smart pointer class would be. You have no option at that point but to have a full definition of ITest. Rename HashImport.h to HashImportFwd.h (like you have ios and iosfwd in the standard library). Then create a new header called HashImport.h containing this:#include "HashimportFwd.h"
#import "libid:00020813-0000-0000-C000-000000000046" version("1.6") auto_search no_dual_interfaces rename("DialogBox", "excelDialogBox") rename("RGB", "excelRGB") rename("DocumentProperties", "excelDocumentProperties") rename("SearchPath", "excelSearchPath") rename("CopyFile", "excelCopyFile") rename("ReplaceText", "excelReplaceText")
struct ITest : public Excel::_Application {};
Now, use HashImportFwd.h where the forward declaration is all that's needed and HashImport.h where you need the full definition.
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
Thanks for all your help Stuart :-D It's working fine! I'm trying to come up with some macros to make it configurable, but the inability to redefine a #define as part of another #define doesn't seem to be possible.
-
Thanks for all your help Stuart :-D It's working fine! I'm trying to come up with some macros to make it configurable, but the inability to redefine a #define as part of another #define doesn't seem to be possible.
Stone Free wrote:
I'm trying to come up with some macros to make it configurable, but the inability to redefine a #define as part of another #define doesn't seem to be possible.
No, it's not - the pre-processor's not that clever (probably just as well, really)
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p