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).
Related
I want to make an app in Swift that simply record via the mic of the iPhone and then play the sound recorded.
For that, I'd like to use the lib Superpowered that is a static library with header files.
For that, I tried to drag and drop the .a and headers files in my project (Xcode create for me a bridging header file), add the .a in "Linked Frameworks and Libraries" in Xcode > Target > General (and so in Xcode > Target > Build phases > "Link Binary With Libraries" too) and index the .h files path in Xcode > Target > Build Settings > Search Paths > Library Search Paths.
But with that I have the error "ld: symbol(s) not found for architecture arm64"
Exactly the same as here XCode: Undefined symbols for architecture arm64 error and I tried all the solutions that I found on the web for that, still no way to compile.
SO !
Superpowered gives us a sample app to show how to mix Objective-C++ and use their lib within a Swift project (Here's a link to the git if you want https://github.com/superpoweredSDK/Low-Latency-Android-Audio-iOS-Audio-Engine).
Here is some screenshots of the sample project with what I understand and what I don't :
The Bridging-Header-File with the prototypes of the methods of the lib that I want to use within my Swift code (I don't like this but if it's the only way...).
The viewController file where the code in Swift is, and where I can create a Superpowered object thank's to the Bridging-Header-File, and call the methods that I've put in it.
And wtf I don't even understand why this Objective-C++ file is here and what it contains. It comes out from nowhere, not even their lib files.
So with this sample project in mind, I've created my own project, here is some screenshots :
The same Bridging-Header-File that in the sample project except that I include SuperpoweredIOSAudioIO.h so I can use SuperpoweredIOSAudioIODelegate.
My viewController file where the code in Swift is, and where I can create a Superpowered object thank's to the Bridging-Header-File, and call the methods that I've put in it.
Until here, it's great, except that I can't for exemple create a SuperpoweredRecorder object. If I try to include the SuperpoweredRecorder.h file in my Bridging-Header-File I have these errors :
So I saw that it is because SuperpoweredRecorder.h includes some .cpp files and I have to create a wrapper for cpp (a little bit like I did with the bridging header, no ?) but that includes a .h and a .mm file and I don't know what I have to put in that .mm file (the code of SuperpoweredRecorder.cpp ? But I don't have access to it)
So yes, I'm a little bit confused with all that stuff, can you help me to understand how can I use all the Superpowered lib in my Swift project please ?
As I said in comment to #OmniProg, I had a little conversation with the CTO of Superpowered that helped me a lot to find the solution below.
So, as Swift cannot interact directly with C++ but can with Objective-C, I had to create objects in Objective-C++ (.mm file, a mix between C++ and Objective-C) that wrap C++ classes of the lib Superpowered.
Here is an example with the SuperpoweredRecorder object from the lib :
Here I create a .h file where I prototype my wrapper with the name SuperpoweredRecorderWrapped, and I also prototype in it all the methods of the SuperpoweredRecorder of the lib that I want to use.
Then I create a new .m file that I rename .mm and I implement SuperpoweredRecorderWrapped on it.
I import both SuperpoweredRecorderWrapped.h and SuperpoweredRecorder.h.
I create a SuperpoweredRecorder object as property named _wrapped and in my methods, I call the corresponding method of the _wrapped object.
With that, when I'll call start of a SuperpoweredRecorderWrapped in my Swift code, this one will call start of _wrapped, a SuperpoweredRecorder object. See the trick ?
And finally I include all the wrapped classes in my Bridging-Header, like that I can instantiate my wrapped objects from Swift.
NOTE: All the C++ code HAVE to be in .mm files, that's why I make my #include of .h that contains C++ code in my .mm file and not in my .h file.
I haven't programmed in Objective-C++, but I do have experience with C, C++, Objective-C, and Swift, so here are some observations and ideas based on looking at the Superpowered SDK and sample code.
A bridging header lets Swift interface directly with Objective-C, and since Objective-C is a strict superset of C, this implies interfacing with C as well. However, you cannot interface directly with C++, and that's where Objective-C++ comes to the rescue. From what I'm seeing you can mix Objective-C and C++ code in Objective-C++, which allows Objective-C to use C++ classes.
Now on to some specifics.
The bridging header in the SuperpoweredFrequencies example that you looked at introduces a new Objective-C class, Superpowered, which is not part of the library, but of the example, and is implemented in Superpowered.mm. It is an Objective-C++ file, because Superpowered calls some C++ code.
Looking at Superpowered.mm, you will see that it imports Objective-C headers:
#import "SuperpoweredFrequencies-Bridging-Header.h"
#import "SuperpoweredIOSAudioIO.h"
as well as C and C++ headers:
#include "SuperpoweredBandpassFilterbank.h"
#include "SuperpoweredSimple.h"
We could have used import instead of include for C++ code, too, but they are probably using include just to emphasize that it is C++ code. Looking at SuperpoweredBandpassFilterbank.h, we see that SuperpoweredBandpassFilterbank is a C++ class. It is used in Superpowered.mm by the Superpowered Objective-C++ class, see the filters member, which is a pointer to a SuperpoweredBandpassFilterbank object.
In the project you attempted to build, I see where the Superpowered interface is declared in the bridging header, but I don't see an implementation. The failure to #import SuperpoweredRecorder.h is due to SuperpoweredRecorder.h being a C++ header. The #include should be in your Objective-C++ (.mm) file, it's useless in the bridging header, since Swift can't make sense of C++ anyhow.
Hopefully this is helpful. Welcome to the world of C++.
I'm a bit surprised that you would have to provide prototypes of method.
I used Objective C libraries in my Swift project before and I only had to add the header files in my bridging header.
See example from my project. The bridging header contains just that:
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "QTouchposeApplication.h"
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <FBSDKLoginKit/FBSDKLoginKit.h>
#import <VungleSDK/VungleSDK.h>
I have some legacy C++ code.
I have DLL Bob.
I also have program Jane.
Program Jane imports Bob through his TLB file.
#import 'Bob.tlb'
Why does Jane use Bob like that?
Why doesn't Jane use Bob like this?
#import 'Bob.dll'
I have the source code for both sides.
Thanks for any help or pointers!
#importing a dll is equivalent to importing a tlb only when the dll contains the type library as the resource of ITypeLib type, as dictated by LoadTypeLib API call.
This is not always the case:
the dll doesn't have to contain the tlb as the resource
you might want to use a managed dll via COM interop: the dll doesn't contain the tlb and you have to generate it using tlbexp tool
there are probably other scenarios
TLB is type definition, which also can includes in DLL.
If you directly use #import *.tlb or #import *.dll, the MIDL Compiler would generate .tlh and .thi which used in following compiling steps.
It's not a good choice to directly #import.
If you #import the same .tlb in different cpp in same project, would introduce duplication .tlh & .tli files generated.
My project structure
MainProject (ARC)
SubProject(Non-ARC)
Boost library(i.e. Popular C++ library here is a link http://www.boost.org/)
Problem :
One of header file(intrusive_ptr.h) of Boost library has a inline function with "retain" statement(That file is edited by someone and it is working fine in "SubProject(Non-ARC)"). That header file is public, many files of subporjects are imported in "MainProject" and those file has a reference of this header file. So, indirectly that file comes in MainProject which is an ARC based. That's why compiler refuse to compile.
What I know or tried:
I know how to set the non ARC flag but that we can set only for .m file(compilable file only) not on .h file. if somebody could help me or suggest me any out of box solution.
For the persons who are interested in seeing the "intrusive_ptr.h" can find here intrusive_ptr.h. This file is a part of boost library so, suggestion should consider this library as well.
Any help or directions will be appreciated.
You can use the preprocessor to alter your header file using the technique from this answer
#if __has_feature(objc_arc)
//ARC-specific things
#else
//Non-ARC specific things
#endif
If you need Boost facility in some classes you can hide that using Objective-C++. Helper links:
http://philjordan.eu/article/strategies-for-using-c++-in-objective-c-projects
http://support.apple.com/kb/TA45902?viewlocale=en_US
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();
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!