Obtaining .NET call stacks in a COM application

From OPC Labs Knowledge Base
Jump to navigation Jump to search

The procedure described here might be useful to obtain information about the QuickOPC call stacks when the program appears hung. QuickOPC is mainly written in .NET, and its COM objects are exposed as a layer on top of its .NET objects. This means that even if you are using a COM-based tools, such as VB6, Delphi, PHP etc. to access QuickOPC via COM, the underlying code still runs in Microsoft .NET (managed code). The managed get gets compiled to a native code and is afterwards in principle no different from other native code, but if you use a debugger of your COM-based tool, you won't be able to distinguish the .NET code from any other unknown machine code - specifically, it won't have any symbolic information available. This is unfortunate, because in principle, managed code contained in assemblies always comes with relatively rich metadata, including method names. This allows the .NET-aware debugger to display useful information about the managed call stacks even in absence of the source code or symbol files.

In order to resolve this problem, if a COM application appears hung and you suspect that the cause is in the .NET (managed) code, you need to use a debugger for a managed code. The most common such debugger is Visual Studio. Fortunately, you do not have to own a commercial edition of Visual Studio; it appears that a free edition works OK in this respect. We have tested the steps below with Visual Studio Community 2015.

If a COM application appears hung and you suspect that the cause is in the .NET (managed) code:

Part One: Debugger Break

  1. Install Visual Studio.
  2. In Visual Studio, select Debug -> Options. Under Debugging -> General, uncheck "Enable Just My Code". Press OK.
  3. Start your application. Make sure you do NOT run your application under a debugger that could conflict with a Visual Studio debugger.
  4. In Visual Studio, select Debug -> Attach to process.... Press the Select... button that is to the right of "Attach to:" edit box. Select the "Debug these code types:" radio button, and make sure that "Managed (v4.6, v4.5, v4.0)" is checked. In addition, if the issue also involves the (COM-based) OPC Classic (OPC Data Access, OPC Alarms&Events), also make sure that "Managed Compatibility Mode" is checked. Close the dialog by pressing the OK button.
  5. Under Available processes, select the process of your application. Press the Attach button.
  6. Reproduce the problem with your application.
  7. In Visual Studio, perform the Debug -> Break all command (there is also a "Pause"-like button for it on the toolbar, and Ctrl+Alt+Break keyboard shortcut). You may get a warning message indicating that there is no code to display. Ignore it.
  8. Continue to Part Two (there are two alternatives you can choose).

Part Two: Information Gathering - Through Minidump

  1. Perform the Debug -> Save Dump As command.
  2. In the Save Dump As dialog, make sure that the Save as type is set to Minidump with Heap (*.dmp). Select file name and location, and press the Save button.
  3. Send us the minidump file for analysis.

Part Two, Alternative: Information Gathering - Through Thread List

  1. Perform the Debug -> Windows -> Threads command. The Threads window will open.
  2. You should now see the list of running threads. This is the first interesting piece of information. In the Threads window, invoke the context menu, perform Select All, and then Copy. Save the information from the clipboard for the analysis.
  3. In the Location column, some threads will have "<not available>" indication. There isn't much we can do about them. But, do this for all the remaining threads:
    1. Select the thread in the list, and from the context menu, perform Switch To Thread command (or just double-click on the thread row). The active thread will be marked by a yellow arrow in the second left column of the list.
    2. Switch to the Call Stack window (perform Debug -> Windows -> Call Stack if it is not yet displayed).
    3. Invoke the context menu, perform Select All, and then Copy. Save the information from the clipboard for the analysis, making note of the ID or Managed ID of the thread it belongs to (these are the columns in the Threads list).
  4. Send us the call stacks from the clipboard, for analysis.

(end of the procedure)

See also: Troubleshooting program hangs