Intercepting RegisterClass method in Classes.pas Delphi7 - delphi

Is there a way of doing that? The list of registered classes is in the TRegGroups instance in Classes.pas unit, but problem is that instance is declared in the implementation section of unit. Is there a way of obtaining an address of RegisterClass procedure, or RegGroups.RegisterClass method?

Using KOLDetours.pas you can intercept calls to the method and then call the original method.
You can find it here: http://code.google.com/p/asmprofiler/source/browse/trunk/SRC/KOLDetours.pas
The file contains examples of how to use it.

To answer your specific question:
You may get the address of Classes.RegisterClass simply by using #Classes.RegisterClass as it is exposed in the interface section of Classes.pas.
The address TRegGroup.RegisterClass will be a bit tricky as it is not exposed in the interface section. Using the address of Classes.RegisterClass you could read the offset of TRegGroup.RegisterClass from the compiled code and then calculate the absolute address as a function of Classes.RegisterClass's address. Ultimately, this will be fragile across different version of the compiler.
As an alternative, if you are willing to make a small modification to each package, you could create a unit containing a function named RegisterClass and ensure that the unit is included in your registration unit before Classes.pas. Your unit would then link against your new RegisterClass function which could call some notification method before calling Classes.RegisterClass.
As you have indicated that you are statically linking to the packages, this is all somewhat moot because you will not have an opportunity to connect whatever notification routine you devise. To solve that issue you will want to dynamically load your packages after you have created your splash screen and are prepared to pump messages for it.
Alternatively, you could modify your package registration unit to use InitProc to delay registration until your TApplication instance is created. This would give you an opportunity to create some visual means of indicating registration progress before the registration actually take place.

In a comment you state:
I have 22 packages. Each package has (besides others) a unit with all the units in that package placed in interface section, and a procedure with simple RegisterClass(TSomeClass) for every class in that package.
In which case the answer is obvious. Define your own function, named MyRegisterClass for instance, and call that function instead.

Related

In Spring4D is it possible to register generic interfaces?

I have classes that have a constructor such as
constructor Create(Factory: IFactory<IConnection>)
When I try and register the IFactory in the container
Container.RegisterType<IFactory<IConnection>,TConnectionFactory>
or
Container.RegisterType<TConnectionFactory>.Implements<IFactory<IConnection>>
I get an error stating that the interface does not have a guid.
I don't really want to add lots of pointless interfaces such as
IConnectionFactory = interface(IFactory<IConnection>)
['{45106BA8-43E7-4D26-B0EF-1639871B93E4}']
end;
to get around this but is this the only way?
Many thanks
As you found out the generic interface can have a GUID.
That itself causes no harm until you QueryInterface/Supports IList<string> from something that is an IList<Integer> which would erroneously succeed and subsequently fail once you start working with it. FWIW since you mentioned those types while the collection interfaces all have guids there is no need to ever do such querying when using them but they are required internally which then stays within the same generic type argument.
Currently the GUID is being used to check and get the interface from the implementing object because the RTL only supports doing that with a GUID and not with typeinfo.
In fact following code would not raise an exception during the registration but eventually cause defects when being resolved:
RegisterType<IFactory<IConnection>, TSomeFactory> where TSomeFactory implements IFactory<ISomethingElse>
However there is some rather hidden typeinfo available (see the commented line in System.TInterfaceTable) that has the exact typeinfo of the implemented interfaces. Spring4D internally uses that at some places, for example Spring.Reflection.TRttiTypeHelper.GetInterfaces.
That could be used but then there is another catch: generic types across multiple modules have different typeinfo. So it's not so easy to simply use that information to validate during registration and query the interface from the implementing class because right now the container (via some extension) supports registrations and dependencies across multiple modules.
Making the registration more robust and if possible remove the requirement for having a GUID on the interface is something I have on my list for the container refactoring which is planned for later this year.

Best practice for resolving in Spring4D?

In the spring4d demos, ServiceLocator.GetService<MyType>('Name') is used to resolve the types. But why not use GlobalContainer.Resolve<MyType>('Name')? I don't see any advantage in this approach...
There is one use case, where I use ServiceLocator:
when coding to make legacy code projects unit-testable...
There is an old project, where in mulitiple places, there are constructor calls of an object, which I write tests for (new and changed methods only, in classes, where injection is not possible, e.g. when a Form is created and destroyed in a button event).
In unit-tests, spring4d is helpful to instantiate the class-under-test:
I can use the GlobalContainer in the dpr for the production project and a special (test-only) TContainer-object which is constructed in Testfixture.Setup and destroyed in Testfixture.TearDown... I also re-initialize the global Service-Locator to use my Test-Container (Reason: I have bad experiences to use GlobalContainer in Test, you cannot un-register a type from GlobalContainer in Testfixture.TearDown).
So now, I got a big method in the dpr, where I register all types to GlobalContainer in the production-code project. In the Setup-Method of my test-fixture-class, I register all types needed for the test to my Testing-Container. And in the Methods, that I changed to make them unit-testable, I construct the classes-under-test with ServiceLocator, where formerly constructor-calls where used.
For me, it is the only way to make such a legacy-code project unit-testable... But my strategic goal is to replace most of this code (part-by-part, including the re-initialized ServiceLocators) one day. It is just not possible to replace it now (too much costs, too much risk...).

I found the ComClass, now how do I reference it?

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.

How best to expose a class instance in DWScript

I am putting together a built-in script capability using the excellent Pascal DWScript. I have also add my own Delphi-side class definition (TDemo) to DWScript using:
dwsUnit.ExposeRTTI( TDemo.ClassInfo )
This just works and is a great way of quickly adding properties and methods.
I also wish to add an existing instance in a similar way, so I have created my instance FDemo of type TDemo and then performed:
dwsUnit.ExposeInstanceToUnit( 'Demo', 'TDemo', FDemo );
This looks a promising routine to call but I get an AV from an uninitialised unit table. I've also looked in the unit test code of the SVN source to see the use of this function but to no avail. Can anyone point me at what I should add / change?
ExposeInstanceToUnit has to be used from within the TdwsUnit table initialization, see RTTIExposeTests/ExposeInstancesAfterInitTable for some sample code. It allows directly exposing dynamic instances.
The other approach is to use the Instances collection of a TdwsUnit component, you get design-time support, and more controls over your instances and their lifetime.
Also keep in mind you have to make sure the instances you expose will properly behave even if the script misbehaves, f.i. when the user attempts to manually destroys an instance you exposed, and that instance shouldn't be destroyed. By default ExposeRTTI will map the destructors, so you may want to restrict that by specifying eoNoFreeOnCleanup.
edit: a last approach recently added is to use the TdwsRttiConnector, which basically allows exposing and connection to anything that's reachable through RTTI. That's very lightweight in terms of code to setup, but the downside is you don't get any form of compile-time checks.

Getting a DLL class procedure address in Delphi

I have a DLL file from which I need the memory address of a class procedure. I am getting the handle to the DLL file, but when I use GetProcAddress, I can't get the address of the procedure. I have tried the following strings for the process name parameter:
"ProcName"
"ProcClass.ProcName"
"ProcClass::ProcName"
"ProcInterface::ProcName"
"ProcInterface.ProcName"
In none of the cases have I gotten the memory address of the procedure. I am mostly certain that the procedure is public.
What is the string format for doing this? Would it be easier to declare a function pointing to the external procedure and get the address later? Like this:
procedure ProcName(); stdcall; far; external 'Example.DLL';
ProcPointer := #ProcName;
GetProcAddress only gives you the address for exported functions. Your DLL surely doesn't export the methods of a class!
Use an PE explorer to look for the exported names. For example, use the PE explorer available in GExperts. I've got a "PE Information" menu entry under the GExperts menu.
You are into reverse engineering territory here.
I think that if I were you I would just step through in the CPU view of the debugger, following a call to the method of interest, and find the entry point address. I'd subtract it from the base address of the DLL and that would be the offset. Then to calculate the address at runtime you just add the offset it to the base address of the DLL in memory at that time. You can find out the base address with calls to LoadLibrary or GetModuleHandle.
Why hard code the offset? Well, since you can't modify your DLL it doesn't seem to be too limiting. If hard coding the offset is not viable then there are other means of locating entry points, but I must admit I'm not the world's greatest expert on that.
Finally, when you implement the replacement method, you will need to replace it with a global function/procedure with an extra parameter, the first parameter, which takes the place of Self.
I might be reading this wrong. But it seems to me you wrote the DLL.
You should write a function that is NOT a member of any class, and export it from your DLL. Inside that function, call your class method.
If you didn't write the DLL, you still need to find out what functions it exports, and it is very unlikely any of them were class methods, at least not in Pascal.
If someone wrote a dll in C++ and exported its methods, then you would have to investigate C++ name mangling rules.

Resources