why would you ever use this class from COM is beyond me?
this class is a wrapper around (a COM component) CDO which is directly
usable from native COM.
Sorry, System.Net.Mail does NOT use CDO. It's a pure .NET component. You're
thinking of System.Web.Mail in pre-.NET 2.0.
The point is that with a wrapper component you can access any .NET component
(with a few exceptions) directly including static types, enums, and through
indirect access with Reflection even value types and arrays of value types
which won't even think about working properly in VFP (try updating an array
of objects in VFP - good luck). Using any form of CREATEOBJECT() only will
never let you instantiate those types or call static methods/members.
The point of a wrapper component is that it gives you much more access
beyond what is exposed through COM interop. Using pure COM Interop (ie.
CreateObject()) requires that whatever you're running CreateObject() on is
ComVisible. As already pointed out a lot of useful stuff is *not*
ComVisible. And it's not just code in the core .NET framework - it's also
code in third party libraries and maybe more importantly in generated
interfaces such as Web Service proxies (which in my work at least is the #1
reason to interface FoxPro with .NET in the first place). If you inherit a
..NET assembly that you need to call from a third party you can almost be
guaranteed that it WON'T BE COMVISIBLE.
The point is relying on ComVisible components only is extremely limiting as
to what you can actually do.
There are two areas you are discussing here and they are quite separate
actually.
* Avoiding COM Registration
* Providing .NET type services to Visual FoxPro
The first is handled by the DLL/C++ code I posted which loads the .NET
runtime and allows loading of assemblies and types. This is purely to avoid
COM registration. If you're not adverse to registering components you can
completely skip this step and just use the .NET wrapper component from
FoxPro with CreateObject(). Or you can use reg-free registration to the same
effect. This is semantics. To me using the DLL code is natural because my
tools already rely on a helper Win32 DLL anyway so this is nothing extra
that isn't already in use. To me this is the easiest way to deal with reg
free interop with .NET but this is not even critical.
The other is the ability to instantiate non-COM visible types and access
members that either don't work at all or badly (like arrays). This provides
basic proxy services which is along the same lines what COM Interop does
behind the scenes but through a different path.
Realistically all the value is the second piece with the first piece.
The blog post I made showed just the basics and you need to figure out where
to take this on your own. But I've actually built this out some time ago
into a full class that provides a host of features for calling .NET
components without any sort of registration:
http://www.west-wind.com/webconnection/docs?page=_24n1cfw3a.htm
But using this tool you can - without any special formatting or
requirements - access just about any .NET components:
CLEAR
DO wwDotNetBridge
LOCAL loBridge as wwDotNetBridge
loBridge = CREATEOBJECT("wwDotNetBridge") && Fox wrapper around .NET
component
*** Load an assembly
? loBridge.LoadAssembly("System") && 'System' is a special name and not
really necessary - loaded by default
? loBridge.cErrorMsg
*** Note full load is syntax by 'fully qualified assembly name':
* loBridge.LoadAssembly("System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089")
*** Create an instance of a .NET class
loMsg = loBridge.CreateInstance("System.Net.Mail.MailMessage")
? loBridge.cErrorMsg
*!* ? loMsg
? loMsg.ToString()
*** Load Static Method
? loBridge.LoadAssembly("System.Windows.Forms")
?
loBridge.InvokeStaticMethod("System.Windows.Forms.MessageBox","Show","Hello
World","Title is it")
? loBridge.cErrorMsg
*** Get a Static value (System.Environment.CurrentDirectory)
? loBridge.GetStaticProperty("System.Environment","CurrentDirectory")
*** Get an Enum value (basically a static)
?
loBridge.GetEnumValue("System.Windows.Forms.MessageBoxDefaultButton","Button3")
*** Load one of my own assemblies
?
loBridge.LoadASsembly("C:\projects2005\WebLogBusiness\bin\debug\weblogbusiness.dll")
? loBridge.cErrorMsg
*** Retrieve a static property which is an object
loConfig = loBridge.GetStaticProperty("Westwind.WebLog.App","Configuration")
*** I could also instantiate the config object directly
*loConfig = loBridge.CreateInstance("Westwind.WebLog.App")
? loBridge.cErrorMsg
*** Object now in VFP - just access properties and methods
? loConfig.WebLogTitle
? loConfig.MailServerName
? loConfig.WebLogTile = "Some OtherValue"
*** Set and read a static property on a custom static object
?
loBridge.SetStaticProperty("Westwind.WebLog.App","ApplicationOfflineMessage","NEW
VALUE")
?
loBridge.GetStaticProperty("Westwind.WebLog.App","ApplicationOfflineMessage")
I'd love to see you do a few of these things - like accessing a static
property or getting an enum value - even if you have your main component
registered. With pure COM interop you simply can't do this. A wrapper is
required to act as a proxy for some of these operations.
As Nicholas pointed out - this approach doesn't do away with COM interop.
Everything still happens over COM. The only difference is rather than COM
instantiation firing up and causing the .NET Runtime to be hosted in VFP,
the small C++ component does it. But .NET works just fine passing back
non-COM visible types - the problem with only COM Interop is that you can
only *instantiate* what is ComVisible. The wrapper (the .NET portion of it)
makes it possible to get at almost any component.
+++ Rick ---
----- Original Message -----
From: "Willy Denoyette [MVP]" <
[email protected]>
Newsgroups: microsoft.public.dotnet.languages.csharp
Sent: Wednesday, January 30, 2008 12:13 PM
Subject: Re: Make a DLL in C# for FoxPro