I have written a dll in d-7. It functions correctly. It gets loaded when an application starts and unloaded when it exists.
Now, that dll must also work on the server side of that application, being loaded from the COM+ surrogate (dllhost.exe) as the server is based on com+ technology.
The problem is that one process may have only one handle for loaded library. I cannot have separate handles on each LoadLibrary call.
In com+, one dllhost.exe can serve many clients, which means that if I load an external library it gives the same instance for each clients calls.
So:
1) Is it possible to somehow workaround this problem?
2) Or Is it possible to directly create instance of the class which resides in this dll for each client call?
3) Or How to make a dll thread-safe by instantiating an internal class for each call.
Thanks for suggestions in advance!
Since a DLL uses the local memory of the thread/process that calls it, I'm not sure you're really going to have a "problem". You do not want to have the DLL maintain some global information because that will only lead to threading nightmares.
If you have a function within the DLL return an object reference (effectively a handle) you can also guarantee that each instance gets its own information to play with and not stomp on other processes or threads. Define the function to return your TWhatever object, have the DLL create it ( TWhatever.Create() ) and return it to the calling process. It would then be up to the calling process to free the object. If you need COM+ compatibility then it should be possible to use an interface reference (IWhatever) and return that from your function.
If each thread deals with its own object instance (or interface reference) then you could have the DLL serve as many threads and processes as you wish.
Your question is confusing to me so I'm not sure if I answered it correctly. :p
Related
Currently I'm writing a REST server using a framework of a well-known Delphi component developing company. This framework provides the ability to simply write a class whose methods are named like the REST API endpoints.
The REST server fetches data from a MS SQL Server, I use dbGo components for that (what is ADO behind the scenes). There is also available an ORM framework of the same company mentioned above, but I don't want to use it for reasons.
Some of the REST calls work on a bunch of databases at once. In order to increase performance I implemented a connection pool, holding objects that encapsulate TADOConnection instances. When a REST call gets executed, it queries the connection pool if there is already an existing connection for the database(s) used by the call. If not, the required ADO database connection objects are created and handed over to the connection pool in order to be used again for subsequent connections to the same database(s).
I've noticed that the class with the methods named like the REST API endpoints gets instantiated by the framework for every single REST call. When the call is done the instance is freed. Because object instantiation and method calls are executed in the context of the REST server's thread (not in the main thread), I need to call CoInitializeEx in the constructor of the class and CoUninitialize in its destructor to be able to use dbGo's TADOxxx classes. Please note: There is no way to hook the server's thread creation or termination (I know, these would be the correct places to call CoInitializeEx and CoUninitialize, respectively).
The above concluded means that I store TADOConnection objects (encapsulating an ADO ActiveX class) during a certain cycle of CoInitializeEx/CoUninitialize and reuse them in a later cycle, i.e. COM has been uninitialized and gets initialized again between two usages of the same TADOConnection object.
Now my question is: Could that lead to any problems in a production scenario (for example crashes, memory or handle leaks or similar unwanted things) if multiple clients access the REST server? I'm quite unexperienced in dealing with COM and ActiveX respectively, so I need some help.
I'm implementing a DLL containing a shared ADO Connection by using the ConnectionObject property of TADOConnection and passing it across DLL boundaries into other instances of TADOConnection. I need to make sure COM is initialized, so I need to call CoInitialize / CoUninitialize. Currently it's in the context of a VCL main thread, but could be elsewhere in another thread, which of course requires its own instance of COM. I'm not currently implementing multi-threading.
Where is the appropriate place to call these; inside the DLL (during loading/unloading), outside the DLL (calling process), or both? Considering it's only one thread, shouldn't it be only one time outside the DLL in the original process?
I'm assuming the original calling thread should be solely responsible for this, since COM runs in the context of a thread. Of course calling them on both sides shouldn't hurt any, however it would also create multiple COM instances.
Long story short... Is it "safe to be safe" in this case? Or is it important to only keep one COM instance?
You should not be doing this in the DLL. Make it part of the contract between the DLL and the host that the host is responsible for initializing COM.
The DLL cannot be expected to initialize COM because the host may already have done so. And use a different threading model. Once COM has been initialized then future attempts to initialize will fail if they attempt to change the threading mode.
So, don't initialize COM in your DLL. Require the host to do so.
Delphi.
How from DLL to learn Handle the appendix which has caused this DLL?
That is necessary: Knowing Handle appendices, I wish in Dll to use this Handle at creation of dialogues, because dialogue created as TOpendialog.Create(nil) sometimes it appears under the main window of the basic form. And so, in DLL I would make:
application.handle:=GetExeHandle; // GetExeHandle - How to learn?
Opendialog1:=TOpendialog.Create(application);
...
So it is correct?
The only time your DLL shows a dialog box is when the host application calls a function from your DLL. Include the parent window handle as one of the function's input parameters so that the EXE can tell you which handle to use. Do not attempt to discover the handle yourself. As a library developer, you cannot guess what the host application is doing.
If you don't want to include the handle on every function call, then add an initialization function that users of the DLL need to call before any other functions. Pass the handle in the initialization and then store it in a variable in your DLL so that other functions can use the value when they need it.
Unless you use runtime packages (and you don't, or not the right ones), you are in for a world of pain.
Your library will have its' own copy not only of (T)Application but also of thread sycnhronization queue and event (and everything else).
What you are trying to do can seem to work, but it may (and it will) break anytime cause any complex dialog, regardless if VCL or WinAPI, does its' own message pumping, which will bypass the applications' idle and synchronization handling, resulting in reentrancy issues and random stalls or deadlocks.
You may try to handle a lot of the cases by copying the applications' handles, events etc. to the DLL's globals upon its' initialization (is I tried to do), but (not only) if you use anything like TApplication or TThread in the DLL, it will break sometimes.
You can avoid these problems if you use the right BPL runtime packages in your app and the library, as they will share the same namespace and globals as the application using them.
I'm currently attempting to integrate a DLL (FooEmulation) into an existing project.
The DLL assumes that it will only be used to emulate one Foo at a time, and uses a lot of static globals as a result.
However, I want to be able to manage thousands of Foo instances at once.
I have the source to the original DLL, so I could convert all of the static globals into parameters that would be passed in (whether directly or via a handle), but the DLL is being maintained separately and I'd like to avoid forking/merging if at all possible.
One technique I found was to load multiple dynamically generated copies of the DLL, but that is too resource-heavy for the scale I need.
I also can't afford to create a process or thread for each Foo.
Is it possible to keep multiple copies of the DLL's static memory and restore it per use of the DLL?
How do I locate it? Am I even allowed to touch it?
When you load the DLL multiple times into the same process all the static data is shared, period. You'll have to redesign the library so that all those objects can be created dynamically as you need them during the runtime.
I am assuming you're on windows since there's nothing telling me otherwise..
Take a look here, which is the documentation for DLLMain in Windows.
DLLMain has a parameter that tells you if
A process is attaching (loading your DLL)
A process is detaching (unloading your DLL)
A thread is attaching (loading the per thread parts of your DLL)
A thread is detaching (unloading the per thread parts of your DLL)
If you catch the process or thread events and allocate (attach) / free (detach) a new instance of your statics, I think this would solve your problem. It's a little hacky, but it would work...
You have to be careful what you do in DLLMain as well. Look in the docs for the warnings about blocking in any way in DLLMain.
Just want to confirm with the COM/DCOM experts out there...
I have a Delphi COM EXE that is running on a server (threading is Single Apartment) and another copy of that same EXE starts up on the same server
(a server that has say 2 processors with dual core so the task manager shows 4 separate graphs) will they take turns waiting for each other or will they run on separate cores?
I found a post somewhere that said
"If two clients need to use the same object, they have to take turns. With this threading model the instance data is safe, global data must be protected using critical sections or some other form of serialization. Of course, the thread's local variables are reliable across multiple calls."
You've missed the "different objects from the same server" part from the same paragraph. Since you have "Single instancing" you get a separate server for each COM object instance, so calls to those instances can be processed in parallel and COM will not have to provide any mutual exclusion.
Think of it this way. Threading models are there to provide thread safety - synchronized access to data shared between threads of the same process. You have one object per process, so there's no two threads will try to access the same object unless of course you try to pass a pointer to one object into another object method call.