This project only contains the VisualFoxPro related code. If you want the c# code for interop library go to https://github.com/voxsoftware/jxshell.dotnet4
Go to Spanish documentation
Yes made .NET interop easy for VisualFoxPro 9
kodnet adds a small library that allows you to use classes/objects and .NET controls within your VisualFoxPro 9 project. You can call any method, field or property of any .NET class without having to create a COM component. Access the .NET framework components, the large number of free .NET libraries, or your own components from VisualFoxPro 9 without registering or installing anything.
kodnet even allows access to enums, structs, classes and generic methods, which is something you can't achieve by generating a .COM component yourself. kodnet implicitly provides type conversion whenever possible and also provides wrappers that allow you to use native .NET types but not native to VisualFoxPro 9. This is very useful for example with methods that accept byte, float, long, Decimal among others.
kodnet offers advantages not offered by wwDotnetBridge
- Easier code to write! Call/assign methods, properties, fields using the member's own name.
- Support to create delegates and add/delete events
- Create generic class instances easily
- Real support for asynchronous .NET methods
- Compile C# code dynamically
- Support for including visual controls from .NET to VFP forms
- Up to 8 times faster in instance method calls See example
If you are thinking migrating, and need professional help, contact us at our email address above. We will be happy to create an affordable quote to fit your needs.
If you need any specific requirement or want to contribute to this project continue improving you can contact us at [email protected] or use the donation link. If you wish to become a sponsor and have your logo/company appear in this README.md, become a sponsor that donates monthly and contact us.
kodnet runs on .NET Framework 4 or higher and any version of Windows that supports this framework and VisualFoxPro 9
Load the kodnet environment
* Load kodnet library
do fullpath("kodnet.prg")
If you get a message that says Unable to load CLR it's probably because Windows blocks files downloaded from the Internet. To do this right-click on the .DLL libraries distributed with kodnet and click unlock.
* you can now access to kodnet using _screen.kodnet
local WebClientClass, WebClientObj
* you get a reference to static class calling getStaticWrapper
m.WebClientClass = _screen.kodnet.getStaticWrapper("System.Net.WebClient")
* create an instance of WebClient
m.WebClientObj = m.WebClientClass.construct()
* Download Google's home page
m.WebClientObj.DownloadFile("https://www.google.com", "Sample.html")
* load an assembly by file
local customClass, customObject
_screen.kodnet.loadAssemblyFile("customdotnet.dll")
m.customClass= _screen.kodnet.getStaticWrapper("CustomClass")
* create an instance of type
m.customObject= m.customClass.construct()
* call customObject's method
? m.customObject.customMethod()
* access to property, methods, fields directly
local int32Class
m.int32Class= _screen.kodnet.getStaticWrapper("System.Int32")
? m.int32Class.MaxValue
? m.int32Class.MinValue
- Access any .NET component even if it is not marked for interop [ComVisible].
- You do not need to register or install the component
- Call any method, property directly like any other object FoxPro
- Calling the constructor of a class with parameters is possible
- Call any method overload. kodnet select the best, according to your parameters
- Support for any non-native .NET type
- Access to static members, including Structs, Enums, Generics, etc.
- Access .NET arrays easily using Get and Set methods
- You can pass an object FoxPro and read it from a .NET method using dynamic.
- Multithread support
- Include visual .NET controls within your VisualFoxPro forms and access your members like any other .NET class.
- Support for adding/deleting .NET event handlers (delegates)
- Great performance in method calls, properties, because internally it doesn't use Reflection but uses CallSite (the methodology it uses internally dynamic in C#)
Download the project to see the examples and learn how to use it. It mainly consists of the following
- ClrHost.dll - Win32 dll to load the .NET runtime
- DLLs used for interop - The lib folder
- kodnet.prg - FoxPro prg, frontend to Proxy
- dotnet4.vcx - FoxPro Visual Class, for adding .NET controls to forms
In a distributed application, it is recommended that you distribute the kodnet components within a folder called kodnet in the same location as your executable.
Take a look at an example of code that uses different features of .NET components
do fullpath("kodnet.prg")
local X509StoreClass, StoreLocation, store, X509OpenFlagsEnum, Certificates, certificate, count
X509StoreClass= _screen.kodnet.getStaticWrapper("System.Security.Cryptography.X509Certificates.X509Store")
* access to enum
StoreLocation= _screen.kodnet.getStaticWrapper("System.Security.Cryptography.X509Certificates.StoreLocation")
store= m.X509StoreClass.construct(StoreLocation.LocalMachine)
* OR use this for certificates only the user
*store= m.X509StoreClass.construct(StoreLocation.CurrentUser)
X509OpenFlagsEnum= _screen.kodnet.getStaticWrapper("System.Security.Cryptography.X509Certificates.OpenFlags")
m.store.Open(X509OpenFlagsEnum.ReadOnly)
* manage collections
Certificates= store.Certificates
count= Certificates.Count
?"Certificates found: " + str(m.count)
FOR i=1 TO m.count
* use item for access to collection items
certificate= m.Certificates.item(m.i - 1)
if (!ISNULL(m.certificate))
? m.certificate.FriendlyName
? m.certificate.SerialNumber
? m.certificate.GetName()
endif
endfor
Consider now a more advanced example that calls asynchronous methods and uses .NET events.
* KODNET ([email protected])
* Download File asynchronous example
do fullpath("kodnet.prg")
LOCAL netClientClass, netClient, uriClass, downloadCallbackObj, downloadCallback, file
* select a file
file= GETFILE()
IF EMPTY(m.file)
RETURN MESSAGEBOX("Please select a file",64,"")
ENDIF
uriClass= _screen.kodnet.getStaticWrapper("System.Uri")
netClientClass= _screen.kodnet.getStaticWrapper("System.Net.WebClient")
m.netClient= m.netClientClass.construct()
downloadCallbackObj= CREATEOBJECT("downloadCallback")
* create a delegate that point to VisualFoxPro function
downloadCallback=_screen.kodnetManager.createeventhandler(m.downloadCallbackObj, "finished", "System.ComponentModel.AsyncCompletedEventHandler")
* add the event handler
m.netClient.add_DownloadFileCompleted(m.downloadCallback)
* this method is a .NET async method, this call will complete without finish the download
m.netClient.DownloadFileAsync(uriClass.construct("http://storage-ns01.d0stream.com/.drive/Projects/ffmpeg.tar.gz"), m.file)
* this executes before finish for demostrate that method is called async
? "Download has started. Running in background"
return
DEFINE CLASS downloadCallback as Custom
FUNCTION finished(sender, args)
* avoid memory leaks (this is only required for objects not forms)
this._event.destroy()
IF !ISNULL(args.Error)
MESSAGEBOX("Failed download: " + args.Error.Message, 48, "")
ELSE
? "download finished"
MESSAGEBOX("Finished download.", 64, "")
ENDIF
ENDFUNC
ENDDEFINE
kodnet allow C# code dompilation. Take a look in this example
TEXT TO m.code noshow
using System;
public class program{
public static void main(){
}
}
namespace Compiled
{
public class Person{
public string name;
public int age;
}
public class Test
{
public Person person(string name, int age){
var p= new Person();
p.name= name;
p.age= age;
return p;
}
public static int ExecuteFunc(Func<string,int> func)
{
return func("Method executed from .NET");
}
public static int ExecuteFunc(Func<string,int> func, string message)
{
return func(message);
}
public static int ExecuteFunc(Func<string,int,string,int> func, string message, int option, string title)
{
return func(message,option,title);
}
}
}
ENDTEXT
LOCAL engine
* COMPILE C# CODE
Local asem, test, person
engine= _screen.kodnet.getStaticWrapper("jxshell.csharplanguage").construct()
m.engine.Runscript(m.code)
asem = m.engine.getCompiledAssembly()
_Screen.kodnet.loadAssembly(m.asem)
* now you can use the type compiled
test= _screen.kodnet.getStaticWrapper("Compiled.Test").construct()
person= test.person("James", 24)
?person.name
?person.age
kodnet supports the creation of delegates and generic objects. In the following example you will see how the class compiled in the previous example is used, to show the use of delegates and generic types: System.Func<string,int>.
* YES! KODNET SUPPORTS DELEGATES
LOCAL Func1, Func2, target , TestClass, needrunCompile
TRY
* Take a look in compilecsharp.prg example for understand
TestClass= _screen.kodnet.getStaticWrapper("Compiled.Test")
CATCH TO ex
needrunCompile= .t.
ENDTRY
IF needrunCompile
RETURN MESSAGEBOX("Please execute first 'compilecsharp.prg' example",64,"Kodnet")
ENDIF
target= CREATEOBJECT("func_callback")
Func1= _screen.kodnet.getStaticWrapper("System.Func<System.String,System.Int32>").construct(m.target,"callback")
Func2= _screen.kodnet.getStaticWrapper("System.Func<System.String,System.Int32,System.String,System.Int32>").construct(m.target,"callback")
* Pass Func1 delegate to c# function
?TestClass.executeFunc(Func1)
* pass overloaded
?TestClass.executeFunc(Func1, "Parameter sent to c#")
* pass overloaded System.Func<string,int,string,int>
?TestClass.executeFunc(Func2, "Parameter sent to c#", 64, "Title")
* It's a good practice Free delegate, avoid memory leaks
Func1.dispose()
Func2.dispose()
DEFINE CLASS func_callback as Custom
FUNCTION callback( str, option, title )
IF PCOUNT() == 3
RETURN MESSAGEBOX(str,option,title)
ELSE
RETURN MESSAGEBOX(str)
ENDIF
ENDFUNC
ENDDEFINE