As a laboratory automation specialist I often encounter projects that deviate from what most people would call standard software development. Some of the systems I contribute on are custom made from the material handling hardware to the control systems, and especially the software. In fact, my colleagues and I spend a great deal of time overcoming some very complex problems integrating the hardware systems with software control systems. I recently had the opportunity to work on a project that required the use of a .NET assembly designed to drive a Programmable Logic Controller. This would normally be very straight forward; however, due to the systems performance requirements the control software had been designed in native C++. This left only a few possible solutions for integrating the .NET assembly.
Obviously, There are several ways to call managed code from native C++ via interop methods such as Platform Invoke or COM. The real issue with these methods is the inherent complexities with memory management on the managed code. One of the main issues involves memory management on the heap due to the CLR automatic garbage collection. Objects on the CLR heap do not maintain the same memory address throughout their entire lifetime. In these instances, the use of interior and pinning pointers are used to either relocate the pointer in the prior or prevent the relocation of the object at run time.
Another method of C++/CLI interop is to create a mixed mode application that blends managed and unmanaged C++ without the use of a COM wrapper or PInvoke. This requires no changes to the native code but will require significant changes to the compiler directives (a search on google will provide the basic project template). In my case this is the method that was used to integrate the .NET assembly into the native application. I chose this method primarily due to my own particular needs for this project. The assembly was only needed in one function that read some inputs and manipulated some outputs based on that read. In this case the fact that the object would only have function scope did not present a significant design challenge. In fact, the only major hurdle was Microsoft Visual Studios crippled C++ CLR intellisense, but that is another story altogether.
In all interop methods there was significant data conversion considerations. The native C++ and managed C++ worlds have significant departure in most of the non-intrinsic types. Managed Strings are specifically vulnerable to problems due to the CLR's handling of string literals. The real issue is that managing pinning pointers and interior pointers will quickly become tiresome in my opinion. So unless you need a global reference to a managed class, this method may not be worth the extra work. I am interested in hearing other stories of C++ interop and how each was handled. Please comment with your experiences.
No comments:
Post a Comment