HOOPS for C# Developers
HOOPS C# supports consists of C# wrappers to HOOPS/3DGS, HOOPS/MVO, HOOPS/Stream, and HOOPS/Parasolid. This guide discusses specific language features associated with developing with HOOPS in C#. Some familiarity with HOOPS/3DGS and HOOPS/MVO is assumed.
Please see the release notes for information regarding the required version of the .NET framework.
Compilation and Execution
The following steps are required to compile and run a C# based application:
Compiling: Your application must reference the HOOPS/3DF C# wrapper classes.
All 3DGS applications:
- hoops<version>_cs<Visual Studio version>.dll
- hics<version>_cs<Visual Studio version>.dll
Applications using HOOPS/MVO:
- hoops_mvo<version>_cs<Visual Studio version>.dll.
Applications using HOOPS/Stream:
- hoops_stream<version>_cs<Visual Studio version>.dll.
Applications using HOOPS/Parasolid:
- hcsp_bridge<version>_cs90.dll.. Note that the Parasolid Bridge is only supported for Microsoft Visual Studio 2008 (VC 9).
Executing: Ensure that the following native .dlls are in your application's directory or in your PATH.
- All 3DGS applications:
- hoops<version>_vc<Visual Studio version>.dll
- Applications using HOOPS/MVO:
- hoops_mvo_mgk<version>_vc<Visual Studio version>.dll
- Applications using HOOPS/Stream:
Applications using HOOPS/Parasolid:Note that the Parasolid Bridge is only supported for Microsoft Visual Studio 2008 (VC 9).
- hoops_stream<version>_vc<Visual Studio version>.dll
- hp_bridge<version>_<Parasolid version>_vc90.dll
The above files are located in your <hoops>/bin/nt_i386_vc<Visual Studio version> directory.
As described in this link (http://msdn.microsoft.com/en-us/library/xwb8f617.aspx), we create our dev_tools* .NET assemblies as "Strong-Named Assemblies". Advantages:
strong-named assemblies contain public key and digital signature (created with the TS3D private signing key)
- the public key combined with the assembly name/version allow an application to uniquily reference a strong-named assembly; this is similar to a GUID, and hence the name "strong-named"
- the public key combined with the digital signature allows the .NET runtime to verify that the .dll bits were not tampered with (ie, modified)
- strong-named assemblies can be placed in the global assembly cache (GAC)
- customer built strong-named assemblies can reference HOOPS/3DF strong-named assemblies
Tech Soft 3D keeps a private copy of the signing key generated by the Microsoft sn.exe tool. However, the affected strong-named assembly projects all reference this signing key. Customers can provide their own strong name key .snk file if they need to re-build any Tech Soft 3D strong-named assembly. If they do not provide one, a custom pre-build event is in place which will auto-generate a new random .snk file.
The projects expect the .snk file to be at the top-level HOOPS/3DF directory with the name signing_key.snk: $(HOOPS_INSTALL_DIR)\signing_key.snk
The routines and classes of the HOOPS/3DGS, HOOPS/MVO and HOOPS/Stream toolkits are all generally accessible via the C# wrappers, with a few exceptions and notes covered below. Developers should refer to the Reference Manual for each component, and can additionally leverage the Intellisense capability of Visual Studio to dynamically access listings of class members and function/method argument while programming.
You should also add this "define" to your document somewhere:
Then, for 64 bit projects, you should define the _M_X64 (you can name this anything you want). You should use "HLONG" in all places where you would normally use a C "long". This is because C#'s "long" is always 64 bit, whereas C's "long" is often 32 bit, and are incompatible. Using HLONG will help ensure compatability. (You can also simply use ints for 32 bit projects and longs for 64 bit projects, but things may get confusing).
Each routine name, such as ::Insert_Polyline in your HOOPS program must have a prefix before the name will actually be usable on your computer system. The prefix varies depending on which language you're calling from, and sometimes depending on the brand of the language you're calling from. When calling from C#, all calls to the HOOPS/3DGS API are made through the HCS class, such as:
HOOPS Routines Available in C#
Most functions available under C are available in C# except for:
Two functions are different under C# than C:
Both take an HCSU.ErrorFunc object (which is a delegate) as their argument. If null is passed to ::UnDefine_Error_Handler, it will remove the default HOOPS error handler. HCSU.ErrorFunc denotes error functions that take proper C# string arrays as arguments as opposed to unsafe C# pointers. If an already registered HCSU.ErrorFunc is passed, that handler will be removed.
Here is an example of declaring an error handler:
NOTE: You may have to set your project to "allow unsafe code" in order to use the error handler, as it uses pointers.
You must call Define_System_Options("multi-threading=full") as your first HOOPS call. This is because C# apps must be thought of as multi-threaded, since the garbage collector will run on a separate thread and may trigger HOOPS calls on a separate thread if it invokes certain destructors.
Pointers and write-back values
The largest difference between using HOOPS with C# and C is found when you have a write-back value, i.e. you pass a pointer to a function and it writes a value or values to that location. In HOOPS C#, arrays can typically be written to without any extra help, while single variables need a "ref" keyword before the object name (similar to the "&" operator in C/C++).
For example, the C HOOPS code that uses a char*:
is replaced in C# by StringBuilder:
NOTE: The "StringBuilder" type is used for write-back values. You should use the "string" type for constant string values. These are enforced by the function signatures, so you should not be able to pass in the wrong type.
The C HOOPS code that uses &[float_value]:
is used in a similar manner in C#, with the "out" keyword:
Arrays can be used in C# in a similar manner as they are used in C. The following C code...
...is written in C# by:
Another difference between using HOOPS with C# and C is found when dealing with HOOPS keys. In C#, you should use HLONG (assuming you defined it as mentioned in the previous section). Thus, the C code:
is replaced in C# by:
Datatype Names and Language Declarations in C#
The C# datatypes translate as follows:
|HOOPS||HOOPS (HC) type||C# type|
|'string'||const char *||string|
|'writes string'||char *||StringBuilder|
|'string'||unsigned short const *||string|
|'writes string'||unsigned short *||StringBuilder|
|'HC_KEY'||HC_KEY||HLONG (System.Int32 / System.Int64)|
|'writes int'||&int||out int|
|'writes float'||&float||out float|
|'writes bytes'||unsigned char *||sbyte|
In general, users should not use these methods since HOOPS may end up holding a pointer to managed memory which may be de-allocated or relocated by the C# garbage collector.
If it is essential for you to use any _By_Ref variants, you must ensure that your memory is not affected by the garbage collector. This can be achieved by using the C# fixed keyword, or by using GCHandle.Alloc.
HOOPS Intermediate Mode
The HOOPS Intermediate Mode library provides a means for an application to trap the HOOPS update cycle at certain points in the rendering pipeline through a set of callback classes. When you trap the update cycle at a callback point, you can decide what and how something is drawn, or even abort the process itself. The HOOPS I.M. library also provides a set of functions you can call from your callback class to draw to the display in an "immediate mode" style and to query the graphics database and the device characteristics.
In the HOOPS/3dGS Programming Guide, you can learn more about HOOPS I.M. and how to
implement and use the callback classes.
Protected Class Members
When using the C# wrappers, protected members of a parent HOOPS/MVO or HOOPS/Stream class can be accessed just like any member from a child class.
Accessing Overloaded Virtual Methods
Support for overriding virtual methods of C#/Java classes is enabled via our use of a C++ wrapper-concept called 'directors'. Directors are currently only enabled for a subset of C#/Java classes. Developers can see which classes have directors enabled by examining the directors.i files at each of the following locations.
Garbage Collection and the Dispose method
In C#/Java, the garbage collector takes care of all the memory management for purely C# or Java objects, thus you don't need to explicitly clean them up. However, for native/unmanaged resources, such as the HOOPS C#/Java wrappers which wrap C++ objects (e.g. HOOPS/MVO and HOOPS/Stream objects, callback classes, etc...), the garbage collector may cleanup such objects, but will do so in an undeterministic order.
For example, each time you create a C# HBaseView, a C++ HBaseView is created. The C++ object stays until HBaseView.Dispose() is called, or until the garbage collector calls it for you. But due to dependencies, certain objects need to be destroyed before others. Another example is that HBaseView needs to be deleted before HBaseModel, which should in turn be deleted before the HDB.
Therefore, C#/Java developers need to be aware that they must explicitly call Dispose() or delete() as if it were a C++ program, in order to trigger the C++ destructor. Additionally, objects should be destroyed in the reverse order they were created. (C#/Java developers who work with unmanaged resources/JNI may already be accustomed to this).
On a related note, users cannot expect objects to stay around when passed as arguments to MVO/Stream functions, such as with a Set operation (for example, SetHandleOperator). If the user does not manually store a reference to the object that was passed to the function in their application, then code may unexpectedly fail at times due to garbage collection. For example:
Array Handling in C#
Notes on MVO/HStream/BStream/IM methods which return arrays
- C++ methods which return arrays (as a return type) have corresponding methods in C# which return IntPtr
Each C# module (HCSMVO, HCSSTREAM, HCSBSTREAM, HICS) has three extract methods which must be used to obtain the C# array associated with the IntPtr:
- public static float ExtractFloatArray(IntPtr source, int count)
- public static int ExtractIntArray(IntPtr source, int count)
- public static T ExtractArray<T>(IntPtr source, int count)
Example for HShellObject::GetFlist():
Notes on MVO/HStream/BStream/IM array member variables
Array member variables are of type IntPtr and read-only.
HFileInputResult and HFileOutputResult
C# users should use the enum HFileIOResult wherever HFileInputResult or HFileOutputResult are mentioned in our documentation. For example:
HOOPS/MVO Classes in C#/Java
A majority of HOOPS/MVO classes are available in C# and Java. However, a number of HOOPS/MVO classes are not provided due to inherent limitations of creating C#/Java wrappers for C++ classes.
HOOPS/MVO provides the ability create and modify animations. The HOOPS/MVO animation classes that are accessible in C#/Java are HBhvAnimation and HBhvBehaviorManager. These classes give you the ability to build and manipulate a wide variety of keyframe based behaviors as described in sections on Behaviors and Animations and Defining Behaviors in the HOOPS/MVO Programming Guide. The classes associated with animations that are not accessible in C#/Java include:
A number of input and output handlers are not available in C#/Java. They include:
- HUtilityPMI - This class is wrapped in Java, but not in C#. Please see the Java Programming Guide for usage details.
The concept of multiple inheritance is not supported in C# or Java. Thus, access to HOOPS/MVO classes that utilize multiple inheritance is limited. Specifically, these classes were wrapped with only one class inherited. The following is a list of the C++ MVO classes that use multiple inheritance and what single class they now inherit from in C#/Java.
|HOOPS/MVO Class||Parent Class in C#/Java||Parent Classes in C++|
|HBaseView||HUpdateListener||HUpdateListener, HMouseListener, HObjectManipulationListener|
Additionally, the inability to inherit from multiple classes will impede the use of the HEventListener, HEventListenerItem, HEventListenerManager and HEventManager classes. When deriving a class from one of these event classes, it is likely that you will want to derive from another HOOPS/MVO class like HBaseOperator at the same time. Thus, the event classes cannot be used in this manner.
Note that pointers to vlist and vhash are also not accessible via C# or Java.
All the methods needed to use the HOOPS/Parasolid integration module are available in C#. You can read more about them in the HOOPS/Parasolid reference manual.
In the C# interface for HOOPS/Parasolid, you will find that Read_Xmt_File and Write_Xmt_File are not included.
For Read_Xmt_File, we recommend that instead, you use the native Parasolid C# methods to load object into the Parsolid modeler. Once this is complete, then you import them into HOOPS. The following sample code shows how you can do this.
For Write_Xmt_File, we recommend also that you use the native Parasolid C# methods to export information into a file. The following sample code shows how to write an XMT file.
The Read_Xmt_File and Write_Xmt_File methods are used in C# sample programs that integrate with HOOPS/Parasolid.