Currently I have an OCX embedded in our product using standard boilerplate Delphi importing of the OCX. The vendor has issued a new version of the OCX that uses the exact same GUIDs for everything (object and interfaces) but there are changes to the API. These changes are quite limited but I'm having some difficulty coming up with a reliable way to identify if the installed OCX is using the old or new version. The obvious way is to drill into the interface and check if a specific method is available from the object once it has been instantiated. I would like to do this by actually asking the object what the dispatch ID is for a particular method to see if it is present.
I don't want to use the approach of calling a new method and getting an exception as the object won't work until it has been initialised and the initialisation API is one of the things that has changed. This means that any call of a new method before initialisation will fail anyway.
Does anyone know what would be the proper way to poke through the Delphi wrapper and find out if a particular method can be resolved?
The answer is actually in your question:
I would like to do this by actually asking the object what the dispatch ID is for a particular method to see if it is present.
An OCX object implements the IDispatch interface, and IDispatch has a GetIDsOfNames() method for the very purpose of returning the dispatch ID of the object's methods and properties (for use with IDispatch.Invoke()). If a requested name is not known to the object, GetIDsOfNames() returns DISP_E_UNKNOWNNAME.
Related
Is there a standard mechanism with Objective C and the iOS runtime to register setup code?
Why?
The advantage of this is that you can decouple your code nicely.
If a subsystem needs particular setup, the set up stays in that subsystem.
If a group of files need to register that they should all be offered as a particular service, that can be encapsulated in individual files that offer the service and there is no need for a separate configuration file to be kept up to date.
Getting the code to run isn't especially important – I can do that myself with various entry points. What I need is for the compiler or linker or run time or magic to be able to collect up anything that I've registered in different parts of a program, and let me have it when I need it.
How to in c++
With c++, I've typically arranged for this with static instances that are constructed before main() is called. I could use objective-c++, but I'd much prefer to use a standard mechanism.
Thanks.
I would look up:
+ (void)initialize
This method is called whenever a message is first sent to the class meta-object, such as, for example, when alloc-ing an object of that class.
Registering Code
Use the class method +(void) load for components that need to self register themselves.
Note that the load method is run on all subclasses and all categories. This is nothing like the the normal method calling behaviour.
Creating a Registry
If components need to register themselves in some kind of container, use the class method +(void) initialise to create a container to hold the components that are going to register themselves. It seems from my limited testing that initialize can be called before load when a load method uses a class with an initialize method, which is pretty cool if reliable.
Running Registered Code
If the components should do something at some specific entry point of your App, then at that entry point, grab the registered components from the registry and do that thing. Eg, you might extend you UIApplicationDelegate's -(BOOL) application:didFinishLaunchingWithOptions: to actually perform the setup stages the components registered.
In my case, I actually want the registered code to get run every time a specific kind of object is constructed, so I call the registered methods there and let them have the object being constructed.
More references on load and initialise
Thank you for the answers and comments that let me put this answer together.
Quite a lot of detail from Mike Ash, although I was initially put off by his statements about load being "tricky because it runs so early".
A very helpful S.O. question on load and initialize.
Is their a safe way to determine if class / method you are accessing is not restricted at runtime ?
Or
do these classes have some property which you check and safely avoid using them?
E.g. UINavigationTransitionView or UITransitionView are accessible but undocumented, hence I assume you are not allowed to use them.
Uhm, as the name implies, any method or class not documented in the public Apple documentation or in the SDK header files is considered private API and should not be used for AppStore submissions.
Note, that sometimes you may find yourself accessing public methods on private classes. This is generally acceptable, but it depends on your use.
There are also cases, where Apple has opened API and made public retroactively, meaning you can use a method for current SDK as well as call it on previous versions of iOS safely. Examples of this include NSArray's firstObject and NSDatas base64 API.
There's no way to check programmatically at run-time. In order to know whether you're accessing a private API, you'd need to know which SDK the app was built with, and then you'd need to check every function or method call against the headers from that SDK. Since iPhones don't generally have an SDK installed, there's no way to do that check at runtime.
If you use constructions like:
Class transitionViewClass = NSClassFromString("UITransitionView");
then it's impossible to determine it's access level (public or private) at runtime.
It's better to use direct access to classes/methods:
Class transitionViewClass = [UITransitionView class];
In this case compiler that Xcode uses will show warnings/errors that this class is undeclared:
Semantic issue: Use of undeclared identifier 'UITransitionView'
How do I access the Objective-C class interface defanition that is collected from headers at (pre or actual) compile time so I can provide introspection that is true to the defined public interface.
Problem: F-Script, SuperDB, IKBClassBrowser, CBIntrospection use the class_copyPropertyList() family of functions to introspect objects at run time. While powerful, there are drawbacks…
the runtime has no concept of private and public… everything is
returned
I can not see a reliable way to access the to the ObjC types of
method arguments and returns
Goal: I am researching a iOS app to help teach coding via a live / immediate development environment (similar to SmallTalk, F-Script, SuperDB, IKBClassBrowser, CBIntrospection). I want users to introspect objects, send messages, create new objects, and build and run code via a VM. But I want to limit the functionality to public functions (there is no way Apple would approve the app otherwise) and I want to have access to types so I limit so users can only pass legal objects.
My hope is that there is some way to access Clang or the symbol file to pull this information in way I can use it at runtime. It does not have to be fully automated (I will probably want to limit functionality in some ways)
You're encountering one of the distinguishing characteristics of Objective-C: There is no such thing as private or public API. There's only documented API vs. undocumented API. You can call any method on any object at any time, regardless of whether it appears in a header file. Public/private distinctions exist only for the compiler; at run time, they don't exist, and there's no way to reverse the process and discern what the header files might have said.
I have written a push source filter that I use privately in my Delphi 6 application. The application uses the DSPACK DirectShow component library. By privately I mean I simply add instances of the filter directly to my Filter Graph, instead of the filter residing in an external DLL (.ax file).
Should I create a unique class ID (GUID) for each instance of the Filter I create, or is it safe to use the same class ID between all instances created? I am concerned about this because each instance of the Filter creates a local data storage object for holding data queued for the Filter. The local data storage object is written to by other code within the host application thereby pushing data into into the Filter Graph via my push source filter .
I don't now enough about DirectShow to know how method pointers lookups are done to know if my design is safe. When I add an instance of a Filter to a graph directly, does DirectShow store the interface method pointers the Filter Graph will call by object reference, or by the class ID? If it's the former then everything will be fine, but if it's the latter, then that could be a problem if the same instance gets all the method calls. Does anyone know the answer to this design question?
Class identifier is specific to a class, not to class instance. Your filter class should have its own unique identifier, and all instances of the class would share it on runtime. If you are copying code from another project, you need to make sure you replace all existing CLSID, IID, LIBID identifiers with newly generated ones.
i'm developing a custom component, and i'd like to add a published property that would be an array of TQuery (it should be visible in the object inspector). the main feature would be to drop the component on a form and then visually select the queries that are present on the same form, or on any other project form.
is that doable? from what i've seen till now, you can only programatically use such an array property...
UPDATE
first, thanks for your answer Alex!
second, the chatch is that i have to modify an old app someone else created, so i want to tangle with it as little as possible (actually there's a second app i need to "fix" which i was told is twice as big). now for the details: the app has abou 15 forms for various db operations. as you can imagine each form has 2-3 TQuery objects. the problem is that the user must authenticate with the db in order to execute the queries, thus he knows the db user & pwd which is a security flow.
in order to avoid this, an intermediate system has been introduced. one connects & authenticates with it and requests the necessary db data: user, pwd, and database name. my job is to use this system and autologin to the db. the necessary credentials to access this intermediate system are not considered a security flow so i'll read them from an inifile that depends on the environment where it's deployed: test, pre-production, production.
so i placed a TDatabase component on my form, setting its LoginPrompt property to FALSE. the tricky part however is adjusting each TQuery to the diferent database name for each environment before execution..
dunno if i made myself clear but it's the simplest explaination i managed to come up with
thanks,
G
To make life as simple as possible, you may have to grin and bear it once:
Create a datamodule and make sure it gets instantiated before the main form.
Put your TDatabase component on that data module.
Go through all your forms once and
add the database's data module to its uses clause (can be in implementation section).
Change all your TQuery and other database related components once to use the database component from the data module instead of having their own connection strings.
At run time, login as you described via your TDatabase component et voila, all your components will now use these settings automagically (as they are all connected to your TDatabase instance).
Okay, you've added a TDatabase to your project. Now, fill the "DatabaseName" property of TDatabase with some random name. Every TQuery component in your project also has a "DatabaseName" property and fill in the same name in those properties! Now your database and all it's queries will be connected and you could use the TDatabase object to access them all.
Yes, it can be done but you will have to write your own Property editor with it's own input form to manage the data inside the array. There's plenty of information to be found online. And yes, you could create a component that checks for controls on it's parent, allowing you to access those.
But is it practical? Why do you need an array of TQuery components in design time? Maybe you need to rethink your design first, so you're absolutely sure that you need this functionality. (Besides, what's wrong with using a Data Module to contain your queries?)