How to use COM dll in my C++ program - c++

I wish to use a COM dll in my C++ library.
The way I figured going about it, is to #import the dll's .tlb file, which I did :
#import "mycom.tlb" no_namespace
The problem is , I don't quite know where to place this declaration. should it be inside the H file or the CPP file? or maybe the stdafx.h file?
I tried placing it in the .cpp file , just for testing.
in the H file I have this member declared :
ILogicSecuredPtr m_pbLogic;
(where ILogicSecured is the interface I want to work with in my COM dll)
Then I added this in the constructor to instantiate the interface :
CoInitialize(NULL);
m_pbLogic(__uuidof(LogicSecured));
(where LogicSecured is the name of the object that implements the interface)
In the destructor I added :
CoUninitialize();
This won't compile however, no matter where I try to place the #import declaration.
it just doesn't recognize the ILogicSecured object.
I get this error in the H file :
Error 2 error C2146: syntax error : missing ';' before identifier 'm_pbLogic'
I should also mention that when I F12 (in Visual Studio) on the ILogicSecuredPtr declaration, it takes me to the tlh file just fine. So I know it recognizes it.
What am I doing wrong here?
Thanks alot.
Roey

The problem is that when the compiler parses the .h file it has not seen the #import yet. Since your project is small your best bet is to put #import into stdafx.h.
When you press F12 Visual Studio uses Intellisence database information that is formed parsing all the sources in order that might be different from the compilation order. So it's quite typical to have Intellisence know where something is declared and the compiler to not compile it at the same time.

What happens if you import a dll or tlb file is that the preprocessor generates a tlh and a tli file.
If the tlb is stable you could also generate the two files and include the tlh header as if its a normal header.
So the answer is put the #import where you would put the header because it is converted into an include of the tlh file.
I use it in the following way to make myself independent of the location of the MSADO15.dll and added the tlh file to my subversion.
#ifndef __ADO__H
#define __ADO__H
#ifdef REBUILD_ADO_HEADER
#import "C:\Programme\Gemeinsame Dateien\system\ado\MSADO15.DLL" rename_namespace("MyAdoNamespace") rename("EOF","EndOfFile")
#else // REBUILD_ADO_HEADER
#include "MSADO15.tlh"
#endif // REBUILD_ADO_HEADER
// Define ADO Namespace as global
using namespace MyAdoNamespace;
#endif // __ADO__H

In addition to the compile issues you are having, there are other problems with this design.
Generally, C++ libraries should not initialize COM on threads that it does not create. This can cause some nasty, hard to debug side effects. Consider updating the interface spec for your library to indicate that use of certain methods or objects require that COM be initialized. You should also specify the threading model required (STA, Free).
That said - the other thing you need to watch out for is calling CoUnitialize() before your smart pointer goes out of scope. This can also cause some hard to debug side-effects. If you're calling CoUnitialize() in the destructor of an object that contains a COM smart pointer, you'll need to explicitly release and detach the pointer prior to invoking CoUnitialize().
Have fun!

Related

Unknown type name 'class'; did you mean 'Class'?

I'm trying to implement AQRecorder.h class from SpeakHere Apple Xcode project example, but even I rename my implementation class to ext. *.mm and put line with #import "AQRecorder.h" still getting error "Unknown type name 'class'; did you mean 'Class'?" and many others.
Which according to me means that it is not recognized as C++ class.
Any help will be appreciated.
I've just had this exact problem. I had a view controller using the AQRecorder class from AQRecorder.mm.
When I included AQRecorder.h in my view controller these errors occurred. It appeared to me because my straight objective-c view controller (named as a .m file) was including C++ header files the compiler was throwing spurious errors.
There are two solutions. The quickest is to rename the view controller class including AQRecorder.h to be a .mm file, in my case UIRecorderViewController from .m to .mm.
Or, move the following includes:
#include "CAStreamBasicDescription.h"
#include "CAXException.h"
Out of AQRecorder.h into AQRecorder.mm. This means that straight C++ style header files will no longer be included (by reference) in your plain Obj-C source.
Hope that helps, and makes sense.
In my case, this error was caused by cyclical "Import" statements in two classes: the header file for each class included the header of the other class, resulting in the Unknown type name 'ClassA'; did you mean 'ClassB'? error:
This is how my import statements were configured when I got this error. In ClassA.h:
Import "ClassB.h"
In ClassB.h:
Import "ClassA.h"
To fix it, I used the #class forward declaration directive to forward-declare ClassA in ClassB.h (this promises the pre-compiler that ClassA is a valid class, and that it will be available at compile time). For example:
In ClassA.h:
Import "ClassB.h"
In ClassB.h:
#class ClassA;
This fixed the Unknown type name 'ClassA' error, but also introduced a new error: ClassB.m: Receiver type 'ClassA' for instance message is a forward declaration. For example:
To fix this new error, I had to import ClassA.h at the top of the implementation file of ClassB (ClassB.m). Both errors are now resolved, and I get zero errors and warnings.
For example, I now have:
In ClassA.h:
Import "ClassB.h"
In ClassB.h:
#class ClassA;
In ClassB.m:
Import "ClassA.h"
Both error messages are now resolved.
i met the same error with you, hope my solution may help you. The Xcode compiler could compile objective-c & c++ in the "*.mm" file, so you may change all your filename which import "AQRecorder.h"(all direct & indirect) file with ".mm" postfix. But you may not do that, you may find that the relationship between SpeakHereController and SpeakHereViewController is some tricky, i just learned how he used it, that create the SpeakHereController object in a nib file, so SpeakHereViewController file is not have to import the "AQRecorder.h" file. my English is stupid, i hope my answer may help you.
IMPORTANT: Select "Compile Source As" variable in compiler settings and set its value to "Objective-C++".
It looks like this problem is impossible to resolve.
If it is possible to shift #include "myC++.h" into *.mm file then it works.
But if You need to use it from your objectiveC.h file it fails.
I guess this is bug from apple. There is a way to specify *.mm instead of *.m
but there is nothing similar to *.hh instead of *.h
I fixed this problem today.If you #include or #import a C++ *.h file or C++/OC mixed *.h file in YourHeader.h,you MUST have a YourHeader.mm . If not,then all your C++ file and C++/OC mixed file will show compile errors.
Using XCode, it's possible to use the "language" Objective C++, which allows you to mix Objective C and C++.
My solution maybe looks ridiculus, but in xcode 4.2,
To add Apple Audio examples codes, I moved all files individually, and it is worked as a charm!
I mean not dragging whole folder, drag one by one all individual file in a spesific folder.
I resolved this issue the following:
Originally, the files were placed inside the project, but not inside the the correct file structure.
YES, I am aware it is not an actual structre as it is only for visual issues, BUT when i moved the Header and the CPP file inside the PROJ folder all worked.
This problem can be solved by changing the following build settings:
Under Apple LLVM Compiler 4.2 - Language
C++ Language Dialect (Gnu++11 works for me)
C++ Standard Library (Libc++ works for me)
It is also necessary to name the .m files as .mm, if you are letting Xcode use file extension to decide how to compile each file.
From my own experience, following things should be taken care.
Select "Compile Source As" variable in compiler settings and set its value to "Objective-C++" i.e Build Settings->Apple LLVM 5.1 - Language->Compile Source As->Objective-C++ (in Xcode 5.1.1)
Change the relevant files which include a C++ header file from .m to .mm (sometimes you need to change all .m to .mm). This was answered by #Diziet above.
If you face incompatible type errors, explicitly do type casting of the required type. These errors might not have shown up when it was .m file.
Specifically, if you're compiling a NDK C/C++ code, and got:
Unknown type name 'jclass'; did you mean 'class'?
It is very likely that the file containing 'jclass' is #include-ed in .c/.cpp files (directly or indirectly) which are to be built into a library. And the solution is: remove that #include.
This is one of the common mistakes done : Circular dependencies.
Consider an example :
File : B.h
#import "A.h"
File : A.h
#import "C.h"
File : C.h
#import "B.h"
This introduces Circular dependency.
Just redeclare in C.h as :
#class B;

Get functions/objects of imported .tlb

I've got a program which shipped with a .tlb file to access some functions/objects (read variables etc.) with my own C++ program. I did a search and imported the .tlb file with:
#import "MyLib.tlb" named_guids no_namespace
I can also import it by using the libid from oleview.exe (ProgId does not work).
Even if I get some warnings (as follows), my program still runs:
C4278 ['TextOut', 'CreateEvent', 'DeleteFile'] is already a macro; use the 'rename' qualifier
But.. how can I gain access of the functions/objects now?
Sorry I'm a beginner so please be patient.
Does it work somehow with IDispatch? Do I need to import some more dll's or do I need more #include directives?
I'm using Visual C++ 2008 Express.
--
Edit: Ok sorry, I already have access to the header of the objects (I see "Application" in auto completion) but I have no idea how to get the objects.
Object Overview
And I think I found the related wikipedia article.
Importing type library gives you description of all the interfaces and identifiers of that library. Normally you should not include additionally any header files. You should just normally create these interfaces using COM smart pointer and call their methods:
CComPtr pInterface;
pInterface.CoCreateInstance(__uuidof("ClassNameFromTLB"));
pInterface->CallMethod();

_ATL_APARTMENT_THREADED and _ATL_FREE_THREADED conflict

I am developing on an existing C++ COM DLL with VS2008.
the compiler says:
"More than one global threading model defined"
in my StdAfx.h i got this define:
#define _ATL_APARTMENT_THREADED
I initialize COM with this:
CoInitialize(NULL);
but i can't find a define for _ATL_FREE_THREADED. the compiler warning indicates that both must be defined somewhere. but i don't know where to find the _ATL_FREE_THREADED.
any ideas why i get the compiler msg?
thanks juergen
Those symbols are defined inside atlbase.h and atldef.h which reside along with other ATL headers - you can look there and see that there's some simple logic for detecting whether one of those symbols has bee set already and setting a default one.
it does sound like you code somewhere defines _ATL_FREE_THREADED. You could sprinkle...
#ifdef _ATL_FREE_THREADED
#pragma message ("hi")
#endif
... between various include files to see if you can find the one that defines that macro. Before you do that though, have you checked to make sure it's not defined in the project properties (both at project and at cpp file levels)?

Problem using a COM interface as parameter

I have the following problem:
I have to projects Project1 and Project2. In Project1 I have an interface IMyInterface. In Project2 I have an interface IMyInterface2 with a method that receives a pointer to IMyInterface1.
When I use import "Project1.idl"; in my Project2.idl, a #include "Project1.h" appears in Project2___i.h. But this file does not even exist!.
What is the proper way to import an interface defined into other library into a idl file?
I tried to replace the #include "Project1.h" by #include "Project1_i.h" or #include "Project1_i.c", but it gave me a lot of errors.
I also tried to use importlib("Project1.tlb") and define my interface IMyInterface2 within the library definition. But when I compile Project2PS project, an error is raised (something like dlldata.c is not generated if no interface is defined).
I tried to create a dummy Project1.h. But when Project2___i.h is compiled, compiler cannot find MyInterface1. And if I include Project1___i.h I get a lot of errors again!
Apparently, it is a simple issue, but I don't know how to solve it. I'm stuck with that!.
By the way, I'm using VS2008 SP1.
Thanks in advance.
Don't include the *_i.c file from a header. You can do so from a source file (.cpp) as a simple way to get it linked in.
EDIT
You can treat separate IDL files and their products completely independently. There is no need to worry about combining them any earlier than at the stage where you include the ordinary header file generated from each IDL file.
To deal with IDL, you add it to a project. This causes MIDL to run on it, and output a header file. (It will by default also output other things, but they aren't essential).
I recommend that you make your IDL files write their headers out to a single, common include directory, which you can then add to the include path for any projects that need to work with the interfaces.
Then just use #include to pull in the header file for each interface you need. As the common include directory is on the project's path, the nested #include in header2.h will be able to pull in header1.h.

#import'ing msado15.dll, is there another way?

In all ADO C++ code I can find, there is a line
#import "C:\Program Files\Common Files\System\ADO\msado15.dll" no_namespace rename("EOF", "EndOfFile")
I understand that this line "incorporate information from a type library", and that "The content of the type library is converted into C++ classes". What?
I'm also looking for the header file for ADO C++, but I can't seem to find it.
It's been a while since I played with that stuff, so what follows is a bit vague and may even be slightly inaccurate, but I hope it still helps:
The DLL implements COM interfaces, and contains a type library describing those interfaces. Among other things, a type library contains the IDL of those interfaces, which should be compiled to generate C++ header files that your program can use.
The #import directive automates the process of extracting the TLB from the DLL and compiling the interfaces it describes to generate the corresponding C++ headers, and #include-ing the generated headers.
#import will generate the header file for you. In this case have a look for msado15.tlh in the intermediate directory (ie, projectname/debug).