Debugging Synergy .NET Code

This topic includes the following sections:

 

The Visual Studio .NET debugger is used for debugging .NET Framework applications on Windows. See Visual Studio documentation for more information on debugging, and note the following:

Remote debugging

Remote debugging is supported for Synergy .NET. This means you can debug a Synergy .NET program running on a remote Windows desktop system or server. You don’t need to have a Visual Studio project for the program, but the program must be built in debug mode, SDI must be installed on the development machine, and the source file (.dbl) with the code you want to step through must be on the development machine. Note the following:

See Microsoft documentation for more information on remote debugging.

Local variables and the Locals window

Determining whether a system option is set

To determine whether a system option is set for a Synergy .NET program, enter the following in the Visual Studio Immediate window, where OPTION is the number of the system option (see System Options):

Synergex.SynergyDE.SysRoutines.f_option(Synergex.SynergyDE.IntegerDesc.CreateLiteral(OPTION), Synergex.SynergyDE.VariantDesc.notPassedInteger);*

If the option is set, this returns 1. If the option is not set, it returns 0.

Examining the contents of a dynamic memory handle

1. Open the Locals window, expand the dm variable, locate the name of the dynamic memory handle you want to inspect, and note the integer value assigned to it.
2. In the Immediate window, run the following command, where ## is the number assigned to the dynamic memory handle:
Synergex.SynergyDE.SysRoutines.hatml(##).ToString()

The value for the dynamic memory handle will be displayed below the command you entered in the Immediate window.

If your dynamic memory handle contains null values, you will need to write the results to a file. For example:

System.IO.File.WriteAllText("filename", Synergex.SynergyDE.SysRoutines.hatml(##).ToString())

where filename is the path and name of the file you want to create and ## is the number assigned to the dynamic memory handle.

Synergy types in the Visual Studio Memory Usage Tool

The Visual Studio Memory Usage Tool displays information on Synergy types, but it uses different names for these types:

Synergex.SynergyDE.TypeDesc

Synergex.SynergyDE.PinTypeDesc

Synergex.SynergyDE.RefTypeDesc

For example, a decimal will appear as either Synergex.SynergyDE.DecimalDesc, Synergex.SynergyDE.PinDecimalDesc, or Synergex.SynergyDE.RefDecimalDesc.

Synergex.SynergyDE.Gen_Box<ns1.$$_struct1, ns1.$$_wrap_struct1>

The next example is for a boxed structure named struct2 in namespace ns1:

Synergex.SynergyDE.Gen_Couple<ns1.$$_struct2, ns1.$$_wrap_struct2>

Watch and Quickwatch windows

Synergy DBL Integration includes several Synergy-specific commands for use in the Visual Studio Watch and QuickWatch windows:

Command

Information displayed

^ADDR(expression)

The address for a descriptor type variable specified by expression. This works only for .NET types in Synergy records and i, d, and a Synergy types. It is used in a procedure that determines what changed a variable. See SET WATCH functionality in Visual Studio below.

Show channels

Channel information

Show handles

Handle information

Note the following:

.define g_select  Synergex.SynergyDE.UIToolkit.GlobalState.t_selection

So, to examine g_select you would enter the following in the Watch or QuickWatch window: Synergex.SynergyDE.UIToolkit.GlobalState.t_selection.

For information on the Synergy.SynergyDE.tklib.dll library, see Using UI Toolkit with the .NET Framework.

SET WATCH functionality in Visual Studio

In traditional Synergy, if a variable’s value changes, you can find out what changed it by using WATCH variable or SET WATCH variable. But for Synergy .NET, this functionality is not available as the default in the Visual Studio debugger. Instead you must use the SOS debugging extension (which is installed with Visual Studio) as outlined in the following procedure. The SOS command !CLRStack dumps current stack traces for all threads at the point the variable changes. By examining these stack traces, you can find out which routine is writing to the variable.

1. Open your Synergy .NET project in Visual Studio, and locate or create a programmatic break or pause in execution (e.g., a point where the program waits for user input) that happens before the variable’s value is changed. You’ll need a programmatic break or pause to give you time to select Break All in step 7.
2. Set a Visual Studio breakpoint at or before the programmatic break.
3. Start debugging the program (Debug > Start Debugging).
4. When the program breaks, use the ^ADDR( ) command in a Watch or QuickWatch window to get the address of the variable. For example, if the name of your variable is my_alpha, enter the following in a Watch or QuickWatch window:
^ADDR(my_alpha)

Note (or copy) the address in the Value column of the Watch or QuickWatch window. You will use the hexadecimal form of this address to set a data breakpoint in step 8. (If a decimal value is displayed in the Value column, you can right-click on the value and select Hexadecimal Display from the context menu.)

5. Detach from the process (Debug > Detach All).
6. Reattach to the process in native mode: Select Debug > Attach to Process, select the process for your program in the Available Processes area of the Attach to Process window, and then click Select. In the Select Code Type window, select Native and clear all other options. Then click OK to close the Select Code Type window, and click Attach in the Attach to Process window.

Detaching and reattaching is necessary because the debugger runs in managed mode by default but must run in native mode for the data breakpoint set in step 8 to work correctly.

7. Select Debug > Break All. You may get an error (e.g., “The process appears to be deadlocked...”) and a “No Source Available” window. Ignore these; just click OK in the error message and close the “No Source Available” window.
8. Set a data breakpoint (Debug > New Breakpoint > New Data Breakpoint) using the hexadecimal address you got in step 4. For example, if the hexadecimal address from that step is 0x0288F0C0, enter this in the Address field of the New Breakpoint window.

1. Set a breakpoint using the hexadecimal address for the variable.

Set a breakpoint using the hexadecimal address for the variable

9. When the breakpoint is set, continue program execution (Debug > Continue).
10. When the debugger breaks at the breakpoint, you’ll see the message “The following breakpoint was hit....” Click OK in this message box.
11. Select Debug > Save Dump As, and then use the Save Dump As window to save a .dmp file.
12. Stop the debugging session (Debug > Stop Debugging).
13. In Visual Studio, select File > Open > File, and then in the Open File window, select the file you saved in the previous step and click Open.
14. A window opens with the title of the .dmp file. In the Actions section of this window, select Debug with Mixed.
15. Enter the following in the Immediate Window:
.load sos

This loads the SOS debugger extension.

16. Enter the following case-sensitive SOS command in the Immediate Window:
!CLRStack

This writes the stack traces to the Immediate Window.

Note that the program’s debugging session is over, so you won’t be able to continue debugging it.