wwDotnetBridge lets your FoxPro applications easily access .NET code from FoxPro, without having to register .NET Components as COM objects and with the ability to access any .NET type and type members including types that are not directly supported over COM.
wwDotnetBridge still uses COM, but unlike standard COM Interop with .NET you don't have to instantiate objects via COM, but rather you can use wwDotnetBridge to host the .NET Runtime and provide activation services for object instances. This means any object and any type becomes accessible, while COM interop is very limited on what can be accessed and what types are supported.
ComValue and Types that don't work over COM
One of the reasons you want to use wwDotnetBridge rather than raw COM interop is that you get access to types that are not supported via COM. For example, COM has no support for a number of .NET Types and type formats.
Examples of unsupported types include:
- any Value type
- Enum Values
- Any Generic Value or Type
That's a pretty wide swath of types that are inaccessible via COM, but with the help of the
ComValue class it's possible to access these types even though you can't access them natively in FoxPro.
ComValue is a facade that provides a wrapper around a .NET Value. It masquerades as a stand-in for the .NET Value and makes it accessible to FoxPro via helper methods that can set and retrieve the .NET value as something that FoxPro can deal with.
How it works
ComValue works by creating a .NET wrapper object with a
Value property that holds the actual .NET value and methods that allow setting and retrieving that value - or a translation thereof - in FoxPro. The
Value is stored in .NET and is never passed directly to FoxPro because effectively it's not accessible there. Instead you pass or receive a
ComValue instance that contains the Value and has conversion routines that allow access to the Value from FoxPro both for setting and getting value.
The idea is simple: The actual raw Value never leaves .NET and the value is always indirectly accessed via conversions that let you set and retrieve the
Value as something that works in FoxPro. So
DbNull is turned into a
null, or a
Guid into a string and vice versa for example.
One of the nice - but also often confusing - features of wwDotnetBridge is that it will automatically return
ComValue instances for most types that otherwise are incompatible. So when you use wwDotnetBridge's intrinsic helper functions and you pass in or receive back say a .NET
Guid it'll automatically convert that Guid into a
ComValue that is returned instead.
ComValue results are automatically returned with:
loGuid = loBridge.InvokeMethod(loObj,"GetGuid") * Get Guid from ComValue lcGuid = loGuid.GetGuid()
You can pass ComValue objects when using these methods:
For these methods you create a
ComValue instance and set the
Value and then pass that to one of the above methods.
lcGuid = GetAGuidStringFromSomewhere() loGuid = loBridge.CreateValue() loGuid.SetGuid(lcGuid) llResult = loBridge.InvokeMethod(loObj,"SetGuid",loGuid)
It's important to understand that it's wwDotnetBridge that understands
ComValue instances, not .NET, so you can only pass or receive a
ComValue through the above indirect access methods never to a .NET method via direct COM access.
Simple type conversion:
Here's an example of passing a byte/in16 value which natively is not supported back and forth between FoxPro and .NET:
*** Create .NET Object instance loNet = loBridge.CreateInstance("MyApp.MyNetObject") *** Convert the 'unsupported' parameter type LOCAL loVal as Westwind.WebConnection.ComValue loVal = loBridge.CreateComValue() loVal.SetInt16(11) *** Call method that takes Int16 parameter loBridge.InvokeMethod(loNet,"PassInt16",loVal)
ComValue caching for Method and Property Invocation
ComValue also supports setting a ComValue from properties and method results. This is useful if you have a method or property that uses a type inaccessible via COM (like strongly typed or subclassed dataset objects for example). In this case you can call the SetValueXXX methods to fill the ComValue structure and then use this ComValue in InvokeMethod, SetProperty calls which automatically pick up this ComValue object's underlying .NET type.
*** Create an array of parameters (ComArray instance) loParms = loBridge.CreateArray("System.Object") loParms.AddItem("Username") loParms.AddItem("Password") loParms.AddItem("Error Message") *** Create a ComValue structure to hold the result: a DataSet LOCAL loValue as Westwind.WebConnection.ComValue loValue = loBridge.CreateComValue() *** Invoke the method and store the result on the ComValue structure *** Result from this method is DataSet which can't be marshalled properly over COM ? loValue.SetValueFromInvokeMethod(loService,"Login",loParms) *** This is your raw DataSet *? loValue.Value && direct access won't work because it won't marshal *** Now call a method that requires the DataSet parameter loBridge.InvokeMethod(loService,"AcceptDataSet",loValue)
The jist of this is that the DataSet result is never passed through FoxPro code, but is stored in ComValue and then that ComValue is used as a parameter in the InvokeMethod call. All indirect execution methods (InvokeMethod,SetProperty etc.) understand ComValue and use the Value property for the parameter provided.
Caveats with ComValue
The biggest caveat with
ComValue is that it's not obvious that some of wwDotnetBridge's methods automatically return
ComValue instances or expect
ComValue instances to be passed in. If you are calling a .NET Method that expects a
long type value you likely end up passing an integer and wondering why that fails. It fails because it's an unsupported type, but that's not obvious, not easily discoverable and the error message that .NET throws unfortunately also is not conducive to resolving the problem.
Just realize if you call methods that use special types (see list above) and you get messages like
Invalid Method Signature or
Method not Found or
Property 'x' is not found on object Y make sure your signature is correct and examine your .NET signature and make sure the value expected isn't one of the problem children.
So discoverability is not there, but beyond raising awareness with this blog post and the topic in the documentation there's not much I can do unfortunately. I hope this post helps and adds another point of discoverability for this topic.
ComValue is a powerful helper class that enables scenarios that otherwise would not be accessible to FoxPro.