I'm binding a ObjC library and it all works well, but I have one problem.
The ObjC library is using some values that are defined in a separate header.
For example, a header with:
#define SOME_PROPERTY_1 TRUE
#define SOME_PROPERTY_2 TRUE
#define SOME_PROPERTY_3 FALSE
Dependant on these properties, the library will make some changes to the view (so these changes are in the library, not in my C# code).
I would like to have access to these properties from my C# code so that I can change them. Now I need to build my library again if I want to change them and I can't change them dynamically (what the goal is).
Is this possible?
I have searched on this, but I didn't understand the two proposed solutions:
Putting them in my C# code instead of in my binding
-> I assume this is not a solution, because in that case the library will not know about these changes? (no connection)
Binding them as (static) properties
Unfortunately, I don't know how to do this. In this header, these is no Class/Interface, only #DEF statements, so I don't know in which 'class' I should define these properties.
The header is then included in some other ObjC classes. I was trying to see if I could define them there, but it's an interface and properties are not accepted.
So basically, there is a "SomeController" class that I'm binding and the "SomeController.h" is defined as interface
#interface SomeController : UIViewController
And in the "SomeController.m" you then have
#import "Constants.h" //The file with only #DEF statements
#implementation SomeController
{
...
}
Any ideas?
Regards,
Matt
This is not possible, because your SOME_PROPERTY_# aren't actually variables, they're preprocessing directives.
This means that the ObjectiveC preprocessor will replace all instances of SOME_PROPERTY_# in your source code with the value you defined it to be, but there is no SOME_PROPERTY_# variable/constant in the final executable.
For example:
#define SOME_PROPERTY_1 TRUE
void foo ()
{
Bool value = SOME_PROPERTY_1;
}
will be converted to this by the preprocessor:
void foo ()
{
Bool value = TRUE;
}
As you can see there is no SOME_PROPERTY_1 in the converted source code.
This means that you can't change the value of SOME_PROPERTY_# dynamically.
Related
I'm trying to import a COM interface into VC++. The COM object is from a application called IDEA, but as that is not very easy to get a hold of for others to help me. So I figure that if someone could give me instructions as to how I would do this for Word, it would be equivalent.
IDEA does have a .tlb file, but it would appear that it is incomplete. I can access the COM API using python with an example being something like this:
if __name__ == "__main__":
dbName = "Sample-Employees.IMD"
idea = win32ComClient.Dispatch(dispatch="Idea.IdeaClient")
db = idea.OpenDatabase(dbName) # open db
table_def = db.TableDef() # get table definition
Using the .tbl file, I can get as far as this:
#import "D:\Program Files (x86)\CaseWare IDEA\IDEA\Idea.tlb"
#include "x64\Debug\idea.tlh"
#include "x64\Debug\idea.tli"
void fn()
{
Idea::IIdeaClientPtr client;
auto db = client->OpenDatabase("Sample-Employees.IMD");
db-> // interface not defined
}
Intellisense will complete after the db-> with the following: AddRef, GetIdOfNames, GetTypeInfo, GetTypeInfoCount, Invoke, QueryInterface and Release. Thus, what I mean by an incomplete interface definition.
Now, since the python example states Idea.IdeaClient, and I've seen this with word as well (i.e. word.application), I was thinking that it might be possible to use that. Looking around though, I can't seem to find reference to that using #import. I have seen it being used with CLSIDFromProgID, but that is very manual mechanism. COM SMARTPTRs would be far more preferable.
Is this even possible to do with VC++?
Maybe OpenDatabase returns IDispatch, but interface containing TableDef is still defined in TLB.
In this case you'll need to downcast IDispatch to I-something-containing-TableDef-method.
Use QueryInterface call to get derived interface from IDispatch, not C or C++ casts, such as static_cast.
Otherwise, you'll need to use IDispatch::Invoke. The best help you have is CComPtr<IDispatch> from ATL, this template specialization have Invoke helpers, so that you can do something like this:
CComPtr<IDispatch> p;
p = db;
CComVairant result;
p.Invoke("TableDef", &result);
Or use IDispatch::Invoke as is.
Python aways relies on IDispatch::Invoke and does not use static interfaces, that's why it does not encounter this problem.
I'm writing a grammar for C++ target, however I'd like to keep it working with Java as well since ANTLR comes with great tools that work for grammars with Java target. The book ("The Definitive ANTLR 4 Reference") says that the way of achieving target independence is to use listeners and/or visitors. There is one problem though. Any predicate, local variable, custom constructor, custom token class etc. that I might need introduces target language dependence that cannot be removed, at least according to the information I took from the book. Since the book might be outdated here are the questions:
Is there a way of declaring primitive variables in language independent way, something like:
item[$bool hasAttr]
:
type ( { $hasAttr }? attr | ) ID
;
where $bool would be translated to bool in C++, but to boolean in Java (workaround would be to use int in that case but most likely not in all potential targets)
Is there a way of declaring certain code fragments to be for specific target only, something like:
parser grammar testParser;
options
{
tokenVocab=testLexer;
}
#header
<lang=Cpp>{
#include "utils/helper.h"
}
<lang=Java>{
import test.utils.THelper;
}
#members
<lang=Cpp>{
public:
testParser(antlr4::TokenStream *input, utils::THelper *helper);
private:
utils::THelper *Helper;
public:
}
<lang=Java>{
public testParser(TokenStream input, THelper helper) {
this(input);
Helper = helper;
}
private THelper Helper;
}
start
:
(
<lang=Cpp>{ Helper->OnUnitStart(this); }
<lang=Java>{ Helper.OnUnitStart(this); }
unit
<lang=Cpp>{ _localctx = Helper->OnUnitEnd(this); }
<lang=Java>{ _localctx = Helper.OnUnitEnd(this); }
)*
EOF
;
...
For the time being I'm keeping two separate grammars changing the Java one and merging the changes to C++ one once I'm happy with the results, but if possible
I'd rather keep it in one file.
This target dependency is a real nuisance and I'm thinking for a while already how to get rid of that in a good way. Haven't still found something fully usable.
What you can do is to stay with syntax that both Java and C++ can understand (e.g. write a predicate like a function call: a: { isValid() }? b c; and implement such functions in a base class from which you derive your parser (ANTLR allows to specify such a base class via the grammar option superClass).
The C++ target also got a number of additional named actions which you can use to specify C++ specific stuff only.
I started the project as an MFC Application (for the GUI..), and later added support for ATL.
I then coded a simple ATL-COM object implementing a non registered dual interface using IDispatchImpl, with the 0xfff for Major and Minor, to tell ATL to load the TLB from the EXE.
I skip some details, but at the end, after some debugging I found that the CComTypeInfoHolder::GetTI implementation in atlcom.h was NOT trying to load the TLB from the EXE, but was searching it in the registry. Reason : a m_plibid variable was NOT corresponding to the DECLARE_LIBID macro use in my ATL::CAtlMfcModule declaration.
After some googling I found Bug: CAtlMfcModule::InitLibId() not called and added a call to InitLibId in my module CTOR.
Works fine, now.
Question: Is that a known bug? with a known fix? I am not confortable with my workaround of such an old bug. Is there another way of dealing with that?
UPDATE: additional information, as an answer states there is no bug...
IDispatchImpl Class:
By default, the IDispatchImpl class looks up the type information for
T in the registry. To implement an unregistered interface, you can use
the IDispatchImpl class without accessing the registry by using a
predefined version number. If you create an IDispatchImpl object that
has 0xFFFF as the value for wMajor and 0xFFFF as the value for wMinor,
the IDispatchImpl class retrieves the type library from the .dll file
instead of the registry.
Excerpt from CComTypeInfoHolder::GetTI Implementation in atlcom.h:
if (InlineIsEqualGUID( CAtlModule::m_libid, *m_plibid) &&
m_wMajor == 0xFFFF &&
m_wMinor == 0xFFFF ) {
TCHAR szFilePath[MAX_PATH];
DWORD dwFLen = ::GetModuleFileName(_AtlBaseModule.GetModuleInstance(), szFilePath, MAX_PATH);
[...]
hRes = LoadTypeLib(pszFile, &pTypeLib);
} else {
[...]
hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);
So, it seems clear to me that there is an advertised behavior: use 0xffff for minor and major and ATL will try to load the typelib from module, not from registry, provided that your CAtlModule::m_libid is up todate. How is CAtlModule::m_libid expected to be be up to date? By using the DECLARE_LIBID macros. How does work that macro? by defining a static InitLibId function, which set up CAtlModule::m_libid.
The bug: when your module derives from ATL::CAtlMfcModule, the defined InitLibId function is NOT called (as ATL::CAtlMfcModule is not a class template)
You are correct, if you are using -1 for major/minor versions, then is is assumed that type information would be taken from the binary. This however does not work with MFC projects: DECLARE_LIBID only works up to CAtlMfcModule class but not its descendants.
A quick fix might be like this, in atlbase.h:
//class CAtlMfcModule :
// public ATL::CAtlModuleT<CAtlMfcModule>
template <typename T>
class CAtlMfcModuleT :
public ATL::CAtlModuleT<T>
and then in your project:
//class CMFCApplication1Module :
// public ATL::CAtlMfcModule
class CMFCApplication1Module :
public ATL::CAtlMfcModuleT<CMFCApplication1Module>
If you post it on MS Connect as a bug, you can leave a link here for others to go upvote the bug.
Using the MFCApplication wizard in Visual C++ 2012, if "Generate attributed database class" is checked, a header with some special syntax (attributed C++ classes) are generated, which look like this:
// MFCApplication2Set.h: interface of the CMFCApplication2Set class
//
#pragma once
// code generated on March-05-13, 9:26 AM
[
db_source(L"Provider=SQLNCLI11.1;..."),
db_table(L"dbo.tblEmployee")
]
class CMFCApplication2Set
{
public:
... big list of stuff that corresponds to the fields in your db table omitted ...
}
The above header corresponds to a mostly empty implementation file:
// MFCApplication2Set.cpp : implementation of the CMFCApplication2Set class
//
#include "stdafx.h"
#include "MFCApplication2.h"
#include "MFCApplication2Set.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMFCApplication2Set implementation
That was the WHOLE implementation class. Notice that:
A. No parent class name is specified anywhere.
B. There's some "Visual C++ magic" going on here, that is, as a novice to modern C++, I'm lost.
db_source is documented here but the documentation is pretty thin or at least opaque to me.
Questions:
I was mystified by this syntax when I first saw it, but I figured out it's probably a variant of this Attributes feature in Visual C++. It is that, right?
How am I meant to I use these generated "attributed database class" objects? I found this documentation but if you look carefully at that documentation, that code sample is showing people the Old Way and the New Way, and is not telling me what I want to know which is how to use this new object that the IDE can not give me any documentation or code completion features for. Also since the generated code for the CMFCApplication2Set class generated by the wizard does not reference any types or class names, I'm lost. If I could even use some IDE feature to know what methods and stuff have been Magically Injected into this Magical mystery Object, I'd be better off. The only think I can think to do is to learn the old way and learn all the things you can call from the old two-separate-ATL-types world, and then somehow learn to combine them.
In a nutshell, I'm looking for the minimum syntax I need to know to actually use one of these Attributed Database Class instances, variables, as they are generated in a new MFC app by the wizard. The instance shown below is a member of an MFC document class and CMFCApplication2Set m_MFCApplication2Set is declared as a field inside the MFC document class.
What I have tried is to use this "untyped object". This object appears to have lots of data fields (m_X) and has only one method that shows up in IDE code completion, called GetRowSetProperties. Thanks to whatever magic or injection is going on, this generated Attributed Database Class (which does not visibly inherit anything) is a complete mystery to me at edit time and compile time.
Here's me just trying to inspect this thing to see if it even initialized itself when its constructor ran:
BOOL CMFCApplication2Doc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE;
TRACE( m_MFCApplication2Set.m_AStringFieldName); // outputs NOISE.
return TRUE; }
At compile time and edit time, the IDE gives me NO help about the types involved in this "anonymous" class that inherits from nothing, but which gets lots of secret powers due to some kind of Injection via those attributes I'm guessing. At debug time, I can see that there is more than just a bunch of data fields in this C++ class, but this still doesn't help me know how to use it. A minimal code sample of using one of these to go get a recordset from the database, would be great.
Update: Calling OpenDataSource is fun, because it compiles but the IDE doesn't think it should be valid. Nevertheless, it runs, and returns 0 as the result, but that doesn't actually initialize this CThingyThatVisualStudioGaveYouThatYouDontKnowWhatItIs:
This is a deprecated feature of attributed C++ code. Pre-processor expands code and replaces attributes with actual base classes. If you enable generation of these intermediate files, things are going to be more clear to you:
You will have XXX.mrg.cpp and XXX.mrg.h files generated, which you can review and see the real C++ code forwarded to compiler.
The attributes will be replaced with substituted bases classes, maps like BEGIN_COLUMN_MAP etc. The attributed source code is compact, but the feature is deprecated and looking into expanded code it should be easy (if necessary) to strip the attributes and copy expanded code right into source. It's easy with DB attributes, and more difficult with COM attributes since the internal dependencies are most sophisticated.
I'm working with a third party COM server with its own custom interface that sets and gets structs as some of its properties. As it happens I'm using C++ for the client. I've posted some representative code from the IDL file below with names changed and GUIDs removed.
Is the packing of the structure defined or is it just good fortune that my client code happens to use the same packing settings that the COM server was built with? Would it be likely to go wrong in projects where the default C++ compiler packing settings had been changed? Is there a pragma pack setting that I could use to make sure the client compiler packing settings are correct?
I can't see any packing pragmas or statements in either the IDL or the header file generated from MIDL. What would happen if the client was in C# or VB instead? Is the packing behaviour more clearly specified if called via the IDispatch mechanism?
struct MyStruct
{
int a, b;
};
[
object,
uuid( /* removed */ ),
dual,
nonextensible,
pointer_default(unique)
]
interface IVideoOutputSettings : IDispatch{
[propget, id(1), HRESULT MyProperty([out, retval] struct MyStruct* pVal);
[propput, id(1), HRESULT MyProperty([in] struct MyStruct newVal);
/* other methods */
};
The default packing is along 8-byte boundaries, according to the MIDL command line switch reference here:
/Zp switch # MSDN (MIDL Language Reference)
Other parts of your code are more likely to break first if the pack value is changed, as the IDL file is usually pre-compiled ahead of time, and it is rare that someone will deliberately alter the command line switches given to MIDL (but not so rare that someone could fiddle with the C-scope #pragma pack and forget to restore the default state).
If you have a good reason to alter the setting, you can explicitly set the packing with a pragma pack statement.
pragma Attribute # MSDN (MIDL Language Reference)
It is pretty good fortune that no party has changed any setting that would interfere with the default packing. Can it go wrong? Yes, if someone goes out of their way to change the defaults.
When using an IDL file, the details are typically compiled into a typelib (.tlb), and it is assumed that the platform are the same for both servers and clients when using the same typelib. This is suggested in the footnotes for the /Zp switch, as certain values will fail against certain non-x86 or 16-bit targets. There can also be 32bit <-> 64bit conversion cases that could cause expectations to break. Unfortunately I don't know if there are even more cases out there, but the defaults do work with minimal fuss.
C# and VB do not have any intrinsic behavior to handle information in a .tlb; instead, a tool like tlbimp is typically used to convert COM definitions into definitions usable from .NET. I can't verify whether all expectations succeed between C#/VB.NET and COM clients and servers; However, I can verify that using a specific pragma setting other than 8 will work if you reference a .tlb that was created from an IDL compiled under that setting. While I wouldn't recommend going against the default pragma pack, here are the steps to perform if you'd like a working example to use as a reference. I created a C++ ATL project and a C# project to check.
Here are the C++ side instructions.
I created an ATL project called SampleATLProject with the default settings in Visual Studio 2010, no fields changed. This should create a dll project for you.
Compiled the project to assure that the proper C-side interface files are being created (SampleATLProject_i.c and SampleATLProject_i.h).
I added an ATL Simple Object called SomeFoo to the project. Again, no defaults were altered. This creates a class called CSomeFoo that is added to your project.
Compile SampleATLProject.
I right-clicked the SampleATLProject.idl file, then under the MIDL settings, set the Struct Member Alignment to 4 bytes (/Zp4).
Compile SampleATLProject.
I altered the IDL to add a struct definition called 'BarStruct'. This entailed adding a C-style struct definition with the MIDL uuid attribute, and an entry in library section referencing the struct definition. See snippet below.
Compile SampleATLProject.
From the Class View, I right-clicked on ISomeFoo and added a method called FooIt, that takes a struct BarStruct as an [in] parameter called theBar.
Compile SampleATLProject.
In SomeFoo.cpp, I added some code to print out the size of the struct and throw up a Message Box containing the details.
Here is my IDL for the ATL project.
import "oaidl.idl";
import "ocidl.idl";
[uuid(D2240D8B-EB97-4ACD-AC96-21F2EAFFE100)]
struct BarStruct
{
byte a;
int b;
byte c;
byte d;
};
[
object,
uuid(E6C3E82D-4376-41CD-A0DF-CB9371C0C467),
dual,
nonextensible,
pointer_default(unique)
]
interface ISomeFoo : IDispatch{
[id(1)] HRESULT FooIt([in] struct BarStruct theBar);
};
[
uuid(F15B6312-7C46-4DDC-8D04-9DEA358BD94B),
version(1.0),
]
library SampleATLProjectLib
{
struct BarStruct;
importlib("stdole2.tlb");
[
uuid(930BC9D6-28DF-4851-9703-AFCD1F23CCEF)
]
coclass SomeFoo
{
[default] interface ISomeFoo;
};
};
Inside the CSomeFoo class, here is the implementation for FooIt().
STDMETHODIMP CSomeFoo::FooIt(struct BarStruct theBar)
{
WCHAR buf[1024];
swprintf(buf, L"Size: %d, Values: %d %d %d %d", sizeof(struct BarStruct),
theBar.a, theBar.b, theBar.c, theBar.d);
::MessageBoxW(0, buf, L"FooIt", MB_OK);
return S_OK;
}
Next, on the C# side:
Go to the debug or desired output directory for SampleATLProject and run tlbimp.exe on the .tlb file generated as part of the C++ project output. The following worked for me:
tlbimp SampleATLProject.tlb /out:Foo.dll /namespace:SampleATL.FooStuff
Next, I created a C# console application, and added a reference to Foo.dll to the project.
In the References folder, go to the Properties for Foo and turn off Embed Interop Types by setting it to false.
I added a using statement to reference the namespace SampleATL.FooStuff as given to tlbimp, added the [STAThread] attribute to Main() (the COM apartment models have to match for in-proc consumption), and added some code to call the COM component.
Tlbimp.exe (Type Library Importer) # MSDN
Here is the source code for that console app.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SampleATL.FooStuff;
namespace SampleATLProjectConsumer
{
class Program
{
[STAThread]
static void Main(string[] args)
{
BarStruct s;
s.a = 1;
s.b = 127;
s.c = 255;
s.d = 128;
ISomeFoo handler = new SomeFooClass();
handler.FooIt(s);
}
}
}
Finally, it runs and I get a modal popup with the following string displayed:
Size: 12, Values: 1 127 255 128
To be sure that a pragma pack change can be made (as 4/8 byte packing are the most common alignments used), I followed these steps to change it to 1:
I returned to the C++ project, went to the properties for SampleATLProject.idl and changed the Struct Member Alignment to 1 (/Zp1).
Recompile SampleATLProject
Run tlbimp again with the updated .tlb file.
A warning icon will appear on the .NET File Reference to Foo, but may disappear if you click on the reference. If it doesn't, you can remove and re-add the reference to the C# console project to be sure it is using the new updated version.
I ran it from here and got this output:
Size: 12, Values: 1 1551957760 129 3
That's weird. But, if we forcefully edit the C-level pragma in SampleATLProject_i.h, we get the correct output.
#pragma pack(push, 1)
/* [uuid] */ struct DECLSPEC_UUID("D2240D8B-EB97-4ACD-AC96-21F2EAFFE100") BarStruct
{
byte a;
int b;
byte c;
byte d;
} ;
#pragma pack(pop)
SampleATLProject is recompiled here, no changes to the .tlb or .NET project, and we get the following:
Size: 7, Values: 1 127 255 128
Regarding IDispatch, it depends on whether your client is late-bound. Late-bound clients have to parse the type information side of IDispatch and discern the proper definitions for non-trivial types. The documentation for ITypeInfo and TYPEATTR suggests that it is possible, given that the cbAlignment field provides the information necessary. I suspect most will never alter or go against the defaults, as this would be tedious to debug if things went wrong or if the pack expectations had to change between versions. Also, structures are not typically supported by many scripting clients that can consume IDispatch. One can frequently expect that only the types governed by the IDL oleautomation keyword are supported.
IDispatch interface # MSDN
IDispatch::GetTypeInfo # MSDN
ITypeInfo interface # MSDN
TYPEATTR structure # MSDN
oleautomation keyword # MSDN
Yes, structs are a problem in COM. If you use IUnknown based interfaces then you'll have to roll the dice with proper compiler settings. Few reasons to change the default.
If you use COM Automation then you have to declare the struct with a typedef in the .IDL. So that the client code can use IRecordInfo to access the structure properly, guided by the type library info. All you have to do is ensure that your compiler's /Zp setting matches midl.exe's /Zp setting. Not hard to do.
You sail around the problem entirely by realizing that any structure can be described by an interface with properties. Now it doesn't matter.