When automating an out-of-process COM server from a client application, if the client code enters a tight loop or makes extensive requests for obtaining new interfaces, the client application might hang during an automation call, requiring the user to terminate the process abnormally. Once hung, any COM request involving a marshaled interface fails. A reboot is required to clear the problem.
The problem only occurs on Windows 95 and Windows 98 systems.
When an interface is marshaled across process boundaries, a number of system objects are created to handle communication between the client and server processes. This includes the proxy/stub, along with the OID and OXID needed by COM to identify the interface being marshaled. When the interface is released by the client process, these objects will be destroyed during garbage collection.
By design, COM uses lazy garbage collection to free system resources that are no longer needed. This collection occurs during periods of relative inactivity. If a client application does not provide adequate free time for garbage collection to occur, it is possible that the system will run out of resources and no longer be able to marshal interfaces. If this happens, the COM layer itself may become corrupt, preventing further garbage collection until the system is restarted.
The most common cause for the problem is that the client's code has entered a tight loop or is performing an intense period of automation involving a nested object hierarchy, where successive calls are being made to get and release numerous out-of-process objects in a short period of time. For example, the following code sample shows a nested object hierarchy that requires three interfaces to be marshaled every time the PrintOut method is called. Because the code runs in a tight loop, the total number of interfaces being marshaled is 30:
For i = 1 To 10
For Windows 95 and Windows 98, the total number of interfaces that can be marshaled at once is approximately 65,536.
Developers need to minimize the number of object references they request during tight loops or heavy periods of automation. If an interface is needed more than once, it should be held on to and used repeatedly rather than released and reacquired several times in succession.
For example, this modified version of the above sample performs the same task but only requires two interfaces to be marshaled for each PrintOut call (a 30 percent reduction from the code above):
Set oBook = oExcel.ActiveWorkbook
For i = 1 To 10
Another possible solution might be to move some of the automation code in-process to the server, if the server allows for in-process scripting. For example, Microsoft Office products incorporate VBA scripting for internal automation. By moving the loop code into a VBA module, you could avoid marshaling multiple interfaces, and instead invoke a macro that lets the server do all the work.
For additional information, please see the following
article in the Microsoft Knowledge Base:
HOWTO: Dynamically Add and Run a VBA Macro from Visual Basic