I have an application and a dll, both written in Delphi 2006.
I have an class that descends from a base class and overrides several virtual methods.
The class is passed to the DLL via an exported method, the exported method only knows about the base class. I call the methods on the class from within the DLL the overridden methods are not invoked.
Is there something I need to do to get this to work? is is it simply not possible?
You can't create an object in one module and call its methods in a different module. By module I mean .exe/.dll.
If you wish to cross boundaries like this, then you need to use packages, COM or free functions. Packages look alluring but bind you into using the same compiler for all packages in the system. If that is not restrictive to you then go ahead and use packages. Otherwise use COM or free functions.
Related
We have an app that makes fairly extensive use of TIniFile. In the past we created our own descendant class, let's call it TMyIniFile, that overrides WriteString. We create one instance of this that the entire app uses. That instance is passed all around through properties and parameters, but the type of all of these is still TIniFile, since that is what it was originally. This seems to work, calling our overridden method through polymorphism, even though all the variable types are still TIniFile. This seems to be proper since we descend from TIniFile.
Now we are making some changes where we want to switch TMyIniFile to descend from TMemIniFile instead of TIniFile. Those are both descendants of TCustomIniFile. We'll also probably be overriding some more methods. I'm inclined to leave all the declarations as TIniFile even though technically our class is no longer a descendant of it, just to avoid having to change a lot of source files if I don't need to.
In every tutorial example of polymorphism, the variable is declared as the base class, and an instance is created of the descendant class and assigned to the variable of the base class. So I assume this is the "right" way to do it. What I'm looking at doing now will end up having the variables declared as, what I guess you'd call a "sibling" class, so this "seems wrong". Is this a bad thing to do? Am I asking for trouble, or does polymorphism actually allow for this sort of thing?
TIniFile and TMemIniFile are distinct classes that do not derive from each other, so you simply cannot create a TMemIniFile object and assign it to a TIniFile variable, and vice versa. The compiler won't let you do that. And using a type-cast to force it will be dangerous.
You will just have to update the rest of your code to change all of the TIniFile declarations to TCustomIniFile instead, which is the common ancestor for both classes. That is the "correct" thing to do.
The compiler is your friend - why would you lie to it by using the wrong type ... and if you do lie to it why would you expect it to know what you want it to do?
You should use a base class that you derive from, like TCustomIniFile. I would expect compile issues if you are trying to make assignments which are known at compile time to be wrong.
The different classes have different signatures so the compiler needs to know which class it is using to call the correct method or access the correct property. With virtual methods the different classes setup their own implementation of those methods so that the correct one is called - so using a pointer to a base type when you call the virtual method it calls that method in the derived type because it is in the class vtable.
So if the code does compile, it's very likely that the compiler will not be doing the right thing ...
I've written a small COM Server in Delphi 2010 that acts as a plug-in into a retail application. The retail application looks for a "discover" interface which registers any number of additional interfaces calling TAutoObjectFactory.Create for each one. This is working just fine--all the plug-in interfaces function as designed.
But now I'd like to call a public method of one interface from another interface so I don't have to duplicate code. Seems simple enough, just call ComClassManager.ForEachFactory looking for the ClassID of the interface I need to use. Got that working, too!
But now that I found the class, I'm stumped by a seemingly trivial final step: how to use or cast the class (or class reference?) I've located to actually call one of its methods.
In the "FactoryProc" I've sent to ForEachFactory, I assume the ComClass property of TComObjectFactory is what I'm after, but it's of type TClass, a class reference to the actual class object to which it points (at least I hope I'm understanding this correctly). I'm a little fuzzy on class references and my attempts to cast or otherwise de-reference this property has resulted in access violations or compiler errors.
Any suggestions?
You're right in your comment, ComClassManager deals with classes, not instances. What you need is (your application-local implementation of) running object table (or something similar), so plugin instances can interact with each other.
How to actually implement it depends on what you really need, e.g. call methods on all running instances, or only on instances of specific classes.
I'm working with some Interop code and need to instantiate an interface.
The equivalent in C# is:
Interop.SomeInterface theInterface;
theInterface = new Interop.SomeInterface();
theInterface.SomeEvent += new SomeEventHandler(...);
How can I accomplish instantiating this interface in F#? Do I need to re-wrap this interop dll into something that F# can make sense of?
It is impossible to instantiate an interface. The C# compiler is pulling a trick by instantiating a class by looking up the implementer of the interface. This is done by the compiler examining the CoClassAttribute.
As far as I know, F# knows nothing about the CoClassAttribute, so you need to change your code so that it instantiates an actual class, not an interface.
You could figure out the class you need by looking at the CoClassAttribute on SomeInterface with Reflector, ILdasm, or any other metadata inspector. If the interop wrapper was generated using tlbimp or visual studio, usually the class will be named SomeInterfaceClass by convention.
Is it possible to let the IDE automatically implement inherited abstract methods in Delphi XE? In Java and C# IDEs it's a common functionality like pressing ALT+SHIFT+F10 in Visual Studio or ALT+RETURN in IntelliJ IDEA.
Without this I always have to look up manually which methods have to be implemented and copy their declarations, which really is something I shouldn't have to do nowadays!
You can use ctrl+space in the class declaration to get a list of all the methods you might want to override (or implement from an interface). It does however not tell you which is abstract but once you figured that out you will get the declaration for free by selecting the method(s) from the list.
And after that you can of course use class completion ctrl+shift+c to generate the code in implementation section.
No, the Delphi IDE doesn't have an automatic shortcut for this. But, you can use the compiler to make it easier on you.
Define your new class. Then put a line somewhere in your code that says TMyNewClass.Create(whatever). When the compiler parses this, if there are any unimplemented abstract methods on TMyNewClass, it will tell you about them in the compiler warnings.
Would like to know if methods need to be static in a C# assemble to be access from SSRS?
No, you can use both public methods and static methods in a c# class library and reference them from your SSRS report.
You do need to add static methods in a different way than your public instance methods though. You should check out this MS article on custom code use in SSRS. Here is the gist of how to add a static method:
The Classes section is only for
instance-based members. It is not for
static members. Static (also referred
to as "shared" in some of our
Reporting Services documentation)
means that the member is available to
every instance of the class and every
instance uses the same storage
location. Static members are declared
by using the shared keyword in
Microsoft Visual Basic and the static
keyword in C#. This can be a bit
confusing. What this means is, if your
custom assembly contains instance
members that you need to access, you
will have to specify the class name
and instance name in the Classes
section. Because the method I will be
calling from Reporting Services was
defined as static by using the shared
keyword in Visual Basic, I'll use the
References section instead of the
Classes section.
So, if you want to do an instance method, make sure to add the refrence, but also specify a "Class" and "Instance name" in the Classes section of Report Properties for every method you need. Then call them using an expression of =Code. Like so:
=Code.InstanceName.Method
Hope that will help you out.