Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

.NET Framework Interop


  • Please log in to reply
155 replies to this topic
sp
  • Members
  • 52 posts
  • Last active: Jun 10 2011 02:05 PM
  • Joined: 07 May 2011
This is an updated script. It again introduces MyFunctions.dll and also includes xpath.ahk for XML processing. XML is useful so that you can send it to C# to do further processing and then send it back to Autohotkey for using it with its GUI or process it with the unique capabilities of AutohotKey. The Autohotkey script also populates a List View with the array of values returned from C# to Autohotkey. There are some minor additions too (and OnExit event and a hotkey maping from ^!c to ^!s).

Also, now the included ahk scripts (CRL.ahk and xpath.ahk) will have to be stored in ahk_files and Dll files are stored bin. Both directories reside where you main ahk script resides.

Updated code: This version is the same as the previous one, but it does not use the .NET Dll MyFuncions.dll . It only uses the .NET Dll Mysql.Data.dll . The reason I made this new post is for people that want to run the script, to only have to download Mysql.Data.dll for .NET from mysql.com to do that. Just save MySql.Data.dll in the folder where you will place the autohot script with the code in the post. Also, in the same folder place COM.ahk (the COM_L version for Autohotkey_L ). Remember to also install Autohotkey_L , .NET framework and MySQL and run its server (create in there a database called solontesting and make a table called shares and put data in it, also check that you have a user called root that has no password and that has rights on the database solontesting) to your PC if you haven't already do that. Once you are done, right click on the autohotscript you made, and select Run Script.

Also, to make things clearer, I shoud mention that the script compiles two C# code blocks, once in file (that is necessary if you want to include third party .NET Dlls in your application) and once in memory.



Updated code: Now you can compile the file to .exe and the compiled file will be completetly standalone. It will have in it, the third party DLLs it loads (MySql.Data.dll and MyFunctions.dll) installed in it, the .exe file. Of course it will also have in it, the CRL.ahk file too.

Note that you should have SetWorkingDir %A_Temp%
and when you load the DLLs you should also tell the autohotkey script to find them at %A_Temp%\MySql.Data.dll and %A_Temp%\MyFunctions.dll
. You should also set the CLR_StartDomain to have the AppDomain base path to A_TEMP and finally you should tell CLR_CompileC# to compile C# to exe in the path %A_Temp% .




Updated code: Now compiled C# is loaded only once and the compiled C# classes/instances keep state.




This is for Autohotkey_L

It demonstrates how to write Autohotkey and C# code in an Autohotkey script and connect and query MySql.

The script includes CRL.ahk (CRL_L version, for Autohotkey_L) and also requires Mysql driver for .NET. It also uses another dll called MyFunctions.dll (referenced with using MathFunctions; in C#). The two dll files are simply put in the directory where you will store this script and CRL.ahk. You need to have .NET framework installed in your PC too.






;The #Directives must come before OnExit to work, #include seems to be an exception

#SingleInstance force
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
;SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

SetWorkingDir %A_Temp% ; This is the temp directory of Windows, this is where the Autohotkey application will look for the DLLs it will load and the exe compiled
;inline C# code.

#include ahk_files\CLR.ahk ; For using C# .NET from autohotkey

#Include ahk_files\xpath.ahk ; For XML

; OnExit must enclose all autoexecute code in order for OnExit to call the ExitSub if the user exits tha application
; OnExit Display pop up for confirmation

OnExit, ExitSub




; the following two files are the dlls that C# inline code uses and they will be included in the exe if the ahk script is compiled to exe.
; Note that you still need to have the two DLL files in the original DIR where your uncompiled script is, so that FileInstall will copy them to temp directory
; The compiled exe AutohotKey file will be standalone, without needing to have any files to run.

FileInstall, bin\MySql.Data.dll, %A_Temp%\MySql.Data.dll,1

FileInstall, bin\MyFunctions.dll, %A_Temp%\MyFunctions.dll,1

 
 

c# = 
(

 

 


    using System; 

    using System.Data; 

    using System.Windows.Forms;
	
	using System.Data.SqlClient; 

	using MySql.Data.MySqlClient;
	
	using MySql.Data;
	
    using MathFunctions; // It uses the MyFunctions.dll .



// The class that allows the program to run, Note that other classes are directly accessed though.
class Start
{

Foo myfoo = new Foo();

public static int counter = 0;

  static void Main() 
   {
         
		MessageBox.Show("This program is not standalone. Please run the normal program Test.exe");
   	
		
   }
   
   public void MathFuct(){
   
   int add = AddClass.Add(125,125); // Static call to class in MyFunctions.dll
  int mul = MultiClass.Multiply(25,25); // Static call to class in MyFunctions.dll
  int fac = FactorialClass.Factorial(5); // Static call to class in MyFunctions.dll

  string str = "Addition result = " + add.ToString() + "\n"
       + "Multiplication result = " + mul.ToString() + "\n"
       + "Factorial result = " + fac.ToString();

  MessageBox.Show(str, "Call To MyFunctions.dll");
   
   
   }

   public int Test(int returnInt_, int returnInt2_)
   {
   
    
     int valueFromFooTest = myfoo.calc(returnInt_, returnInt2_);
   
     counter = counter + 1;
	 
	 return valueFromFooTest + counter;
   
   }
	
	public void selectfrommysql()
	{
		
		myfoo.mysql();
		
	}
 
   
  
   
}
 
      
 

	
    class Foo { 
	
	    public static int local = 0;
	        public  Foo() { 
            MessageBox.Show("Hello, world, from secondary class of C#!"); 
        } 
	
	         public int calc(int returnInt, int returnInt2) { 
			 
            MessageBox.Show("Hello, world, from function of secondary class of C#!"); 
			
			local = local + 1;
			 			
			return returnInt + returnInt2 + local;
        } 
	
	  public void mysql() { 
	
	 
	      //create a MySQL connection with a query string   
		  MySqlConnection connection = new MySqlConnection("server=localhost;database=solontesting;uid=root;password="); 
 


			MySqlCommand command = connection.CreateCommand();	

			MySqlDataReader Reader;		

			command.CommandText = "select * from shares";	

			 int x;
			 
			 try 
				
				{
			
					connection.Open();
				
				}
			catch(Exception excp)
				{
					Exception myExcp = new Exception("Error connecting you to " +
                    "the my sql server. Internal error message: " + excp.Message, excp);
					
					MessageBox.Show("C# failed to connect to MySql. " + myExcp);
					
					throw myExcp;
				
									
				
				}

			
		

			Reader = command.ExecuteReader();	
			
           string thisrow = "";

			while (Reader.Read()){	
			
				for (int i= 0;i<Reader.FieldCount;i++)		
				thisrow+=Reader.GetValue(i).ToString() + ",";		
	

				}		

		  
		  //close the connection   
		  connection.Close();
	

	
 
	MessageBox.Show("C# queried Mysql, the results are: " + thisrow); 
	 
	
	 
	
	}
	
		
 
		
    } 

)

; XML holder variables
x = <root><element var="test">Test</element></root>

x2 = <root><element var="test">XML Test 2: showing contents of a node.</element></root>

x3 = (<?xml version="1.0" encoding="UTF-8" ?>
<root>

<item>
<name>!mail</naquotme>
<description>Standard mail reply form</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>!scont</name>
<description>Subject of Contact Exception email</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>!cont</name>
<description>Body of Contact Exception email</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>mll</name>
<description>Cleans up ICT Incident report mail</description>
<scope></scope>
</item>

<item>
<name>pwmll</name>
<description>Cleans up ICT password reset mail</description>
<scope>global</scope>
</item>

<item>
<name>!regards</name>
<description>Best regards, [Your name]</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>tel</name>
<description>telephone number</description>
<scope>global</scope>
</item>

<item>
<name>Pw</name>
<description>Password</description>
<scope></scope>
</item>

<item>
<name>pw</name>
<description>password</description>
<scope></scope>
</item>

</root>)

returnVal := 0

CLR_Start()






c#_dll_file = %A_Temp%\MySql.Data.dll ; Files are found at %A_Temp% because I use FileInstall at the top of the script

c#_dll_fileTwo = %A_Temp%\MyFunctions.dll ; Files are found at %A_Temp% because I use FileInstall at the top of the script

all_dlls = System.dll | System.Windows.Forms.dll | System.Data.dll | %c#_dll_file% | %c#_dll_fileTwo%


Windows_temp_folder = %A_Temp% ; Windows temp directory for storing temporary files, this is where we will store the C# exe compiled code
 
;Start a new AppDomain so we can define the base path to load assemblies from. 
CLR_StartDomain(pApp, A_Temp) ; Base path to load the DLLS with be the temp directory of Windows

CLR_CompileC#(c#, all_dlls, pApp, Windows_temp_folder . "\QueryMySql.exe") 

asm := CLR_LoadLibrary("QueryMySql.exe", pApp)


MsgBox, Hello From AutoHotKey, press control, alt and s to start the demo. Control, alt and q to quit application.

	
	
return ; End of OnExit


; Quits the application
^!q::
ExitApp
return

; continue the application

^!c::^!s ; map keys to the keys that start the application

; Start the application
^!s::
MsgBox, Hello From AutoHotKey, control, alt and s were pressed to run the following.


returnVal := runMainBody(returnVal,asm, x, x2, x3)

return

runMainBody(returnVal,asm, x, x2, x3) ; asm must be passed to a function in order to be able to 

;compile the C# code of variable c# once and be able to keep state

{



 
/* 
 
 Working with XML

*/ 

Msgbox, Working with XML

Msgbox Testing XML processing, first example: changing content.

; Testing XML processing, first example: changing content.
xpath_load(x) ; XML content can be loaded in-place directly

Msgbox Original content

Msgbox, % xpath(x, "element/text()" )

Msgbox, Changing content and showing the whole XML document

xpath(x, "element/text()", "XML Test 1: Content changed")
MsgBox, % xpath_save(x) ; show the new source without having to save it

Msgbox, Second XML example: showing content

; Second XML example: showing content

xpath_load(x2)

node = % xpath(x2, "element/text()")

MsgBox, %node%    


Msgbox Third XML example: looping through XML and showing content

; Third XML example: looping through XML and showing content

xpath_load(x3)

    
Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   hotkeys := xpath(x3, "/root/item[" . A_Index . "]/name/text()")
   description := xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   scope := xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   Msgbox,%hotkeys% %description% %scope%
}

Msgbox Fourth XML example: looping through XML and changing content

; Fourth XML example: looping through XML and changing content

Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   xpath(x3, "/root/item[" . A_Index . "]/name/text()", "Dummy Text")
   xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   
} 

Msgbox, XML changed
 
 ; Save x3 XML
 
 xpath_save(x3)

Msgbox Fifth XML example: looping through XML and showing changed content

; Fifth XML example: looping through XML and showing changed content

xpath_load(x3)

    
Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   hotkeys := xpath(x3, "/root/item[" . A_Index . "]/name/text()")
   description := xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   scope := xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   Msgbox,%hotkeys% %description% %scope%
}
 
 
/*

	Communicating from Autohotkey to C# and vice versa

*/

obj := CLR_CreateObject(asm, "Start") 

obj.MathFuct() ; equivalent to obj["MathFuct"];

obj["selectfrommysql"] ; obj[anything] should be equivalent to COM_Invoke(obj,anything). AutoHotKey_L supports COM natively

returnValue := obj["Test",10, 20] ; obj[anything] should be equivalent to COM_Invoke(obj,anything). AutoHotKey_L supports COM natively

returnVal := returnVal + returnValue

Msgbox, Value given from C#, total is kept in AutoHotKey: %returnVal% 

Msgbox, Value given from C#, total is kept in C#: %returnValue%




MsgBox, Sending arrays to C#, C# will loop through them and display their values, which are
; Sending an array to C#
arr := ComObjArray(8, 2) 
arr[0] := "string 1" 
arr[1] := "string 2" 
param := ComObjParameter(0x2008, ComObjValue(arr))

; Sending a second array to C#

arr2 := ComObjArray(3, 2) 
arr2[0] :=  3 
arr2[1] :=  4
param2 := ComObjParameter(0x2008, ComObjValue(arr2)) 

asm := CLR_CompileC#(LoadC#(), "System.dll|System.Windows.Forms.dll" ) 
obj := CLR_CreateObject(asm, "Test") 

ArrayFromC# := Object()
ArrayFromC# := obj["StringIntTest",arr,arr2]

MsgBox, C# returned arrays to Autohotkey, Autohotkey will loop through them, their values are
For value in ArrayFromC#
    MsgBox  %value%

ArrayFromC# := obj["ReturnString",arr]
For value in ArrayFromC#
    MsgBox  %value%


/*

 Dynamically building a List View from the second C# array returned to Autohotkey

*/ 

Msgbox, Dynamically building a List View from the second C# array returned to Autohotkey

; Create the ListView with two columns, Name and Size:
Gui, Add, ListView, r1 w300 +HScroll +VScroll gMyListView, Name ; Added scrollbars too

; Gather a list of file names from a folder and put them into the ListView:
For value in ArrayFromC#
    LV_Add("", value)

LV_ModifyCol()  ; Auto-size each column to fit its contents.
LV_ModifyCol(2, "Integer")  ; For sorting purposes, indicate that column 2 is an integer.

; Display the window and return. The script will be notified whenever the user double clicks a row.
Gui, Show	
	

; Speech To Text

Text := "Well done. Now you have autohotkey communicate with C Sharp .NET . Press control alt and c to continue the demo." 

SAPI := ComObjCreate("SAPI.SpVoice") 
MsgBox, 0, Rate: 0, Text To Speech 
SAPI.speak(Text) 

return returnVal

}
 

 

LoadC#() { 
c# = 
( 
using System; 
using System.Windows.Forms; 
  
public class Test 
{ 
  public int[] StringIntTest(string[] mystrings, int[] myintegers) 
  { 
     foreach(string mystring in mystrings) 
         MessageBox.Show(mystring); 
   
       foreach(int myinteger in myintegers) 
         MessageBox.Show(  Convert.ToString(myinteger) ); 
		 
		myintegers[0] = 5; 
		
		myintegers[1] = 6;
		 
		return  myintegers;
  } 
  
    public string[] ReturnString(string[] mystrings) 
  { 
		 
		mystrings[0] = "String 7"; 
		
		mystrings[1] = "String 8";
		 
		return  mystrings;
  } 
  
  
} 
) 
return c# 
} 

ExitSub:

    MsgBox, 4, , Are you sure you want to exit?

	IfMsgBox, Yes
        ExitApp
	
	
return

MyListView:
if A_GuiEvent = DoubleClick
{
    LV_GetText(RowText, A_EventInfo)  ; Get the text from the row's first field.
    ToolTip You double-clicked row number %A_EventInfo%. Text: "%RowText%"
}
return


sp
  • Members
  • 52 posts
  • Last active: Jun 10 2011 02:05 PM
  • Joined: 07 May 2011
Updated code: Minor corrections. Now Autohotkey escapes commas from XML when it uses it with xpath.ahk, COM does not display error messages, by setting ComObjError(false), if C# .NET encounters errors (only C# can do that now, if it is programmed to do so in case of error) and DLLs files and the C# compiled from Autohotkey executable are all stored in $temp$/C#AHK where %temp% is the Windows temp directory. This is done to prevent the case where other applications may store Dlls or executable file like the one used by the application, with the same name as the Dlls/executable this application uses that may be of different version or hold different content and thus will cause problems to the application.

This is an updated script. It again introduces MyFunctions.dll and also includes xpath.ahk for XML processing. XML is useful so that you can send it to C# to do further processing and then send it back to Autohotkey for using it with its GUI or process it with the unique capabilities of AutohotKey. The Autohotkey script also populates a List View with the array of values returned from C# to Autohotkey. There are some minor additions too (and OnExit event and a hotkey maping from ^!c to ^!s).

Also, now the included ahk scripts (CRL.ahk and xpath.ahk) will have to be stored in ahk_files and Dll files are stored bin. Both directories reside where you main ahk script resides.


Updated code: This version is the same as the previous one, but it does not use the .NET Dll MyFuncions.dll . It only uses the .NET Dll Mysql.Data.dll . The reason I made this new post is for people that want to run the script, to only have to download Mysql.Data.dll for .NET from mysql.com to do that. Just save MySql.Data.dll in the folder where you will place the autohot script with the code in the post. Also, in the same folder place COM.ahk (the COM_L version for Autohotkey_L ). Remember to also install Autohotkey_L , .NET framework and MySQL and run its server (create in there a database called solontesting and make a table called shares and put data in it, also check that you have a user called root that has no password and that has rights on the database solontesting) to your PC if you haven't already do that. Once you are done, right click on the autohotscript you made, and select Run Script.

Also, to make things clearer, I shoud mention that the script compiles two C# code blocks, once in file (that is necessary if you want to include third party .NET Dlls in your application) and once in memory.



Updated code: Now you can compile the file to .exe and the compiled file will be completetly standalone. It will have in it, the third party DLLs it loads (MySql.Data.dll and MyFunctions.dll) installed in it, the .exe file. Of course it will also have in it, the CRL.ahk file too.

Note that you should have SetWorkingDir %A_Temp%
and when you load the DLLs you should also tell the autohotkey script to find them at %A_Temp%\MySql.Data.dll and %A_Temp%\MyFunctions.dll
. You should also set the CLR_StartDomain to have the AppDomain base path to A_TEMP and finally you should tell CLR_CompileC# to compile C# to exe in the path %A_Temp% .




Updated code: Now compiled C# is loaded only once and the compiled C# classes/instances keep state.




This is for Autohotkey_L

It demonstrates how to write Autohotkey and C# code in an Autohotkey script and connect and query MySql.

The script includes CRL.ahk (CRL_L version, for Autohotkey_L) and also requires Mysql driver for .NET. It also uses another dll called MyFunctions.dll (referenced with using MathFunctions; in C#). The two dll files are simply put in the directory where you will store this script and CRL.ahk. You need to have .NET framework installed in your PC too.


;The #Directives must come before OnExit to work, #include seems to be an exception

#SingleInstance force
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
;SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

SetWorkingDir %A_Temp% ; This is the temp directory of Windows, this is where the Autohotkey application will look for the DLLs it will load and the exe compiled
;inline C# code.


#include ahk_files\CLR.ahk ; For using C# .NET from autohotkey

#Include ahk_files\xpath.ahk ; For XML

; OnExit must enclose all autoexecute code in order for OnExit to call the ExitSub if the user exits tha application
; OnExit Display pop up for confirmation

OnExit, ExitSub


; the following two files are the dlls that C# inline code uses and they will be included in the exe if the ahk script is compiled to exe.
; Note that you still need to have the two DLL files in the original DIR where your uncompiled script is, so that FileInstall will copy them to temp directory
; The compiled exe AutohotKey file will be standalone, without needing to have any files to run.

FileCreateDir, %A_Temp%\C#AHK ; Create directory to hold the Dlls and the C# compiled file, not directly in the Windows temp directory, because other programs may store the Dlls with the same names or different versions, that could cause issues to the application

FileInstall, bin\MySql.Data.dll, %A_Temp%\C#AHK\MySql.Data.dll,1

FileInstall, bin\MyFunctions.dll, %A_Temp%\C#AHK\MyFunctions.dll,1

 

c# = 
(

 

 


    using System; 

    using System.Data; 

    using System.Windows.Forms;
	
	using System.Data.SqlClient; 

	using MySql.Data.MySqlClient;
	
	using MySql.Data;
	
    using MathFunctions; // It uses the MyFunctions.dll .



// The class that allows the program to run, Note that other classes are directly accessed though.
class Start
{

Foo myfoo = new Foo();

public static int counter = 0;

  static void Main() 
   {
         
		MessageBox.Show("This program is not standalone. Please run the normal program Test.exe");
   	
		
   }
   
   public void MathFuct(){
   
   int add = AddClass.Add(125,125); // Static call to class in MyFunctions.dll
  int mul = MultiClass.Multiply(25,25); // Static call to class in MyFunctions.dll
  int fac = FactorialClass.Factorial(5); // Static call to class in MyFunctions.dll

  string str = "Addition result = " + add.ToString() + "\n"
       + "Multiplication result = " + mul.ToString() + "\n"
       + "Factorial result = " + fac.ToString();

  MessageBox.Show(str, "Call To MyFunctions.dll");
   
   
   }

   public int Test(int returnInt_, int returnInt2_)
   {
   
    
     int valueFromFooTest = myfoo.calc(returnInt_, returnInt2_);
   
     counter = counter + 1;
	 
	 return valueFromFooTest + counter;
   
   }
	
	public void selectfrommysql()
	{
		
		myfoo.mysql();
		
	}
 
   
  
   
}
 
      
 

	
    class Foo { 
	
	    public static int local = 0;
	        public  Foo() { 
            MessageBox.Show("Hello, world, from secondary class of C#!"); 
        } 
	
	         public int calc(int returnInt, int returnInt2) { 
			 
            MessageBox.Show("Hello, world, from function of secondary class of C#!"); 
			
			local = local + 1;
			 			
			return returnInt + returnInt2 + local;
        } 
	
	  public void mysql() { 
	
	 
	      //create a MySQL connection with a query string   
		  MySqlConnection connection = new MySqlConnection("server=localhost;database=solontesting;uid=root;password="); 
 


			MySqlCommand command = connection.CreateCommand();	

			MySqlDataReader Reader;		

			command.CommandText = "select * from shares";	

			 int x;
			 
			 try 
				
				{
			
					connection.Open();
				
				}
			catch(Exception excp)
				{
					Exception myExcp = new Exception("Error connecting you to " +
                    "the my sql server. Internal error message: " + excp.Message, excp);
					
					MessageBox.Show("C# failed to connect to MySql. " + myExcp); // Display error message, Autohotkey won't display its own because ComObjError(false) is set later in the code.
					
					throw myExcp;
				
									
				
				}

			
		

			Reader = command.ExecuteReader();	
			
           string thisrow = "";

			while (Reader.Read()){	
			
				for (int i= 0;i<Reader.FieldCount;i++)		
				thisrow+=Reader.GetValue(i).ToString() + ",";		
	

				}		

		  
		  //close the connection   
		  connection.Close();
	

	
 
	MessageBox.Show("C# queried Mysql, the results are: " + thisrow); 
	 
	
	 
	
	}
	
		
 
		
    } 

)

; XML holder variables
x = <root><element var="test">Test</element></root>

x2 = <root><element var="test">XML Test 2: showing contents of a node.</element></root>

x3 = (<?xml version="1.0" encoding="UTF-8" ?>
<root>

<item>
<name>!mail</naquotme>
<description>Standard mail reply form</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>!scont</name>
<description>Subject of Contact Exception email</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>!cont</name>
<description>Body of Contact Exception email</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>mll</name>
<description>Cleans up ICT Incident report mail</description>
<scope></scope>
</item>

<item>
<name>pwmll</name>
<description>Cleans up ICT password reset mail</description>
<scope>global</scope>
</item>

<item>
<name>!regards</name>
<description>Best regards [Your name],</description> <!-- You need to escape a comma with ` Autohotkey requires that -->
<scope>Lotus Notes</scope>
</item>

<item>
<name>tel</name>
<description>telephone number</description>
<scope>global</scope>
</item>

<item>
<name>Pw</name>
<description>Password</description>
<scope></scope>
</item>

<item>
<name>pw</name>
<description>password</description>
<scope></scope>
</item>

</root>)

returnVal := 0

CLR_Start()


c#_dll_file = %A_Temp%\C#AHK\MySql.Data.dll ; Files are found at %A_Temp% because I use FileInstall at the top of the script

c#_dll_fileTwo = %A_Temp%\C#AHK\MyFunctions.dll ; Files are found at %A_Temp% because I use FileInstall at the top of the script

all_dlls = System.dll | System.Windows.Forms.dll | System.Data.dll | %c#_dll_file% | %c#_dll_fileTwo%


Windows_temp_folder = %A_Temp%\C#AHK ; Windows temp directory for storing temporary files, this is where we will store the C# exe compiled code
 
;Start a new AppDomain so we can define the base path to load assemblies from. 
CLR_StartDomain(pApp, A_Temp) ; Base path to load the DLLS with be the temp directory of Windows

CLR_CompileC#(c#, all_dlls, pApp, Windows_temp_folder . "\QueryMySql.exe") 

asm := CLR_LoadLibrary("QueryMySql.exe", pApp)


MsgBox, Hello From AutoHotKey, press control, alt and s to start the demo. Control, alt and q to quit application.

	
	
return ; End of OnExit


; Quits the application
^!q::
ExitApp
return

; continue the application

^!c::^!s ; map keys to the keys that start the application

; Start the application
^!s::
MsgBox, Hello From AutoHotKey, control, alt and s were pressed to run the following.


returnVal := runMainBody(returnVal,asm, x, x2, x3)

return

runMainBody(returnVal,asm, x, x2, x3) ; asm must be passed to a function in order to be able to 

;compile the C# code of variable c# once and be able to keep state

{



 
/* 
 
 Working with XML

*/ 

Msgbox, Working with XML

Msgbox Testing XML processing, first example: changing content.

; Testing XML processing, first example: changing content.
xpath_load(x) ; XML content can be loaded in-place directly

Msgbox Original content

Msgbox, % xpath(x, "element/text()" )

Msgbox, Changing content and showing the whole XML document

xpath(x, "element/text()", "XML Test 1: Content changed")
MsgBox, % xpath_save(x) ; show the new source without having to save it

Msgbox, Second XML example: showing content

; Second XML example: showing content

xpath_load(x2)

node = % xpath(x2, "element/text()")

MsgBox, %node%    


Msgbox Third XML example: looping through XML and showing content

; Third XML example: looping through XML and showing content

xpath_load(x3)

    
Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   hotkeys := xpath(x3, "/root/item[" . A_Index . "]/name/text()")
   description := xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   scope := xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   StringReplace, description, description, ,, `, ; Clean commas from XML, the strange code is produced by xpath in the place of comma for some reason
   
   Msgbox,%hotkeys% %description% %scope%
}

Msgbox Fourth XML example: looping through XML and changing content

; Fourth XML example: looping through XML and changing content

Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   xpath(x3, "/root/item[" . A_Index . "]/name/text()", "Dummy Text")
   xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   
} 

Msgbox, XML changed
 
 ; Save x3 XML
 
 xpath_save(x3)

Msgbox Fifth XML example: looping through XML and showing changed content

; Fifth XML example: looping through XML and showing changed content

xpath_load(x3)

    
Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   hotkeys := xpath(x3, "/root/item[" . A_Index . "]/name/text()")
   description := xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   scope := xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   StringReplace, description, description, ,, `, ; Clean commas from XML
   
   Msgbox,%hotkeys% %description% %scope%
}
 
 
/*

	Communicating from Autohotkey to C# and vice versa

*/

ComObjError(false) ; Disable COM Errors, so that only C# will produce error whenever wanted.

obj := CLR_CreateObject(asm, "Start") 

obj.MathFuct() ; equivalent to obj["MathFuct"];

obj["selectfrommysql"] ; obj[anything] should be equivalent to COM_Invoke(obj,anything). AutoHotKey_L supports COM natively

returnValue := obj["Test",10, 20] ; obj[anything] should be equivalent to COM_Invoke(obj,anything). AutoHotKey_L supports COM natively

returnVal := returnVal + returnValue

Msgbox, Value given from C#, total is kept in AutoHotKey: %returnVal% 

Msgbox, Value given from C#, total is kept in C#: %returnValue%




MsgBox, Sending arrays to C#, C# will loop through them and display their values, which are
; Sending an array to C#
arr := ComObjArray(8, 2) 
arr[0] := "string 1" 
arr[1] := "string 2" 
param := ComObjParameter(0x2008, ComObjValue(arr))

; Sending a second array to C#

arr2 := ComObjArray(3, 2) 
arr2[0] :=  3 
arr2[1] :=  4
param2 := ComObjParameter(0x2008, ComObjValue(arr2)) 

asm := CLR_CompileC#(LoadC#(), "System.dll|System.Windows.Forms.dll" ) 
obj := CLR_CreateObject(asm, "Test") 

ArrayFromC# := Object()
ArrayFromC# := obj["StringIntTest",arr,arr2]

MsgBox, C# returned arrays to Autohotkey, Autohotkey will loop through them, their values are
For value in ArrayFromC#
    MsgBox  %value%

ArrayFromC# := obj["ReturnString",arr]
For value in ArrayFromC#
    MsgBox  %value%


/*

 Dynamically building a List View from the second C# array returned to Autohotkey

*/ 

Msgbox, Dynamically building a List View from the second C# array returned to Autohotkey

; Create the ListView with two columns, Name and Size:
Gui, Add, ListView, r1 w300 +HScroll +VScroll gMyListView, Name ; Added scrollbars too

; Gather a list of file names from a folder and put them into the ListView:
For value in ArrayFromC#
    LV_Add("", value)

LV_ModifyCol()  ; Auto-size each column to fit its contents.
LV_ModifyCol(2, "Integer")  ; For sorting purposes, indicate that column 2 is an integer.

; Display the window and return. The script will be notified whenever the user double clicks a row.
Gui, Show	
	

; Speech To Text

Text := "Well done. Now you have autohotkey communicate with C Sharp .NET . Press control alt and c to continue the demo." 

SAPI := ComObjCreate("SAPI.SpVoice") 
MsgBox, 0, Rate: 0, Text To Speech 
SAPI.speak(Text) 

return returnVal

}
 

 

LoadC#() { 
c# = 
( 
using System; 
using System.Windows.Forms; 
  
public class Test 
{ 
  public int[] StringIntTest(string[] mystrings, int[] myintegers) 
  { 
     foreach(string mystring in mystrings) 
         MessageBox.Show(mystring); 
   
       foreach(int myinteger in myintegers) 
         MessageBox.Show(  Convert.ToString(myinteger) ); 
		 
		myintegers[0] = 5; 
		
		myintegers[1] = 6;
		 
		return  myintegers;
  } 
  
    public string[] ReturnString(string[] mystrings) 
  { 
		 
		mystrings[0] = "String 7"; 
		
		mystrings[1] = "String 8";
		 
		return  mystrings;
  } 
  
  
} 
) 
return c# 
} 

ExitSub:

    MsgBox, 4, , Are you sure you want to exit?

	IfMsgBox, Yes
       {

	   
	   ExitApp


	   }
	
return

MyListView:
if A_GuiEvent = DoubleClick
{
    LV_GetText(RowText, A_EventInfo)  ; Get the text from the row's first field.
    ToolTip You double-clicked row number %A_EventInfo%. Text: "%RowText%"
}
return


sp
  • Members
  • 52 posts
  • Last active: Jun 10 2011 02:05 PM
  • Joined: 07 May 2011
Updated code: In this script, a splashscreen is introduced to display at the beginning of the script for a couple of seconds. A progress bar is placed on top of it, displaying Starting... . Also, the splashscreen is accompanied by a short music clip.

The splashcreen image is saved in folder images as image1.gif and the sound wav file under folder wav as wav1.wav . FileInstall though copies them to C#AHK directory under the Windows temp directory.

A clarification, besides XML, Autohotkey exchange arrays up to 8 dimensions. Of course XML can be seen as an advanced multidimensional array and there are no limits for exchanging that between Autohotkey and C#.

Updated code: Minor corrections. Now Autohotkey escapes commas from XML when it uses it with xpath.ahk, COM does not display error messages, by setting ComObjError(false), if C# .NET encounters errors (only C# can do that now, if it is programmed to do so in case of error) and DLLs files and the C# compiled from Autohotkey executable are all stored in $temp$/C#AHK where %temp% is the Windows temp directory. This is done to prevent the case where other applications may store Dlls or executable file like the one used by the application, with the same name as the Dlls/executable this application uses that may be of different version or hold different content and thus will cause problems to the application.



This is an updated script. It again introduces MyFunctions.dll and also includes xpath.ahk for XML processing. XML is useful so that you can send it to C# to do further processing and then send it back to Autohotkey for using it with its GUI or process it with the unique capabilities of AutohotKey. The Autohotkey script also populates a List View with the array of values returned from C# to Autohotkey. There are some minor additions too (and OnExit event and a hotkey maping from ^!c to ^!s).

Also, now the included ahk scripts (CRL.ahk and xpath.ahk) will have to be stored in ahk_files and Dll files are stored bin. Both directories reside where you main ahk script resides.




Updated code: This version is the same as the previous one, but it does not use the .NET Dll MyFuncions.dll . It only uses the .NET Dll Mysql.Data.dll . The reason I made this new post is for people that want to run the script, to only have to download Mysql.Data.dll for .NET from mysql.com to do that. Just save MySql.Data.dll in the folder where you will place the autohot script with the code in the post. Also, in the same folder place COM.ahk (the COM_L version for Autohotkey_L ). Remember to also install Autohotkey_L , .NET framework and MySQL and run its server (create in there a database called solontesting and make a table called shares and put data in it, also check that you have a user called root that has no password and that has rights on the database solontesting) to your PC if you haven't already do that. Once you are done, right click on the autohotscript you made, and select Run Script.

Also, to make things clearer, I shoud mention that the script compiles two C# code blocks, once in file (that is necessary if you want to include third party .NET Dlls in your application) and once in memory.





Updated code: Now you can compile the file to .exe and the compiled file will be completetly standalone. It will have in it, the third party DLLs it loads (MySql.Data.dll and MyFunctions.dll) installed in it, the .exe file. Of course it will also have in it, the CRL.ahk file too.

Note that you should have SetWorkingDir %A_Temp%
and when you load the DLLs you should also tell the autohotkey script to find them at %A_Temp%\MySql.Data.dll and %A_Temp%\MyFunctions.dll
. You should also set the CLR_StartDomain to have the AppDomain base path to A_TEMP and finally you should tell CLR_CompileC# to compile C# to exe in the path %A_Temp% .






Updated code: Now compiled C# is loaded only once and the compiled C# classes/instances keep state.






This is for Autohotkey_L

It demonstrates how to write Autohotkey and C# code in an Autohotkey script and connect and query MySql.

The script includes CRL.ahk (CRL_L version, for Autohotkey_L) and also requires Mysql driver for .NET. It also uses another dll called MyFunctions.dll (referenced with using MathFunctions; in C#). The two dll files are simply put in the directory where you will store this script and CRL.ahk. You need to have .NET framework installed in your PC too.








;The #Directives must come before OnExit to work, #include seems to be an exception

#SingleInstance force
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
;SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

SetWorkingDir %A_Temp% ; This is the temp directory of Windows, this is where the Autohotkey application will look for the DLLs it will load and the exe compiled
;inline C# code.


#include ahk_files\CLR.ahk ; For using C# .NET from autohotkey

#Include ahk_files\xpath.ahk ; For XML

; OnExit must enclose all autoexecute code in order for OnExit to call the ExitSub if the user exits tha application
; OnExit Display pop up for confirmation

OnExit, ExitSub


; the following two files are the dlls that C# inline code uses and they will be included in the exe if the ahk script is compiled to exe.
; Note that you still need to have the two DLL files in the original DIR where your uncompiled script is, so that FileInstall will copy them to temp directory
; The compiled exe AutohotKey file will be standalone, without needing to have any files to run.

FileCreateDir, %A_Temp%\C#AHK ; Create directory to hold the Dlls and the C# compiled file, not directly in the Windows temp directory, because other programs may store the Dlls with the same names or different versions, that could cause issues to the application

FileInstall, bin\MySql.Data.dll, %A_Temp%\C#AHK\MySql.Data.dll,1

FileInstall, bin\MyFunctions.dll, %A_Temp%\C#AHK\MyFunctions.dll,1

; Wav files

FileInstall, wav\wav1.wav, %A_Temp%\C#AHK\wav1.wav,1 

; Images

FileInstall, images\image1.gif, %A_Temp%\C#AHK\image1.gif

SplashImage,  %A_Temp%\C#AHK\image1.gif, b fs18, AHK + C# Demo and more ;Always on top, but Yes/No exit dialog box if called will be on top of the splashscreen.

SoundPlay, %A_Temp%\C#AHK\wav1.wav

Loop, 300
{
Progress, %a_index%, , Starting..., AHK + C# Demo

Sleep, 1
}

Progress, Off
Sleep 1000
SplashImage, Off


c# = 
(

 

 


    using System; 

    using System.Data; 

    using System.Windows.Forms;
	
	using System.Data.SqlClient; 

	using MySql.Data.MySqlClient;
	
	using MySql.Data;
	
    using MathFunctions; // It uses the MyFunctions.dll .



// The class that allows the program to run, Note that other classes are directly accessed though.
class Start
{

Foo myfoo = new Foo();

public static int counter = 0;

  static void Main() 
   {
         
		MessageBox.Show("This program is not standalone. Please run the normal program Test.exe");
   	
		
   }
   
   public void MathFuct(){
   
   int add = AddClass.Add(125,125); // Static call to class in MyFunctions.dll
  int mul = MultiClass.Multiply(25,25); // Static call to class in MyFunctions.dll
  int fac = FactorialClass.Factorial(5); // Static call to class in MyFunctions.dll

  string str = "Addition result = " + add.ToString() + "\n"
       + "Multiplication result = " + mul.ToString() + "\n"
       + "Factorial result = " + fac.ToString();

  MessageBox.Show(str, "Call To MyFunctions.dll");
   
   
   }

   public int Test(int returnInt_, int returnInt2_)
   {
   
    
     int valueFromFooTest = myfoo.calc(returnInt_, returnInt2_);
   
     counter = counter + 1;
	 
	 return valueFromFooTest + counter;
   
   }
	
	public void selectfrommysql()
	{
		
		myfoo.mysql();
		
	}
 
   
  
   
}
 
      
 

	
    class Foo { 
	
	    public static int local = 0;
	        public  Foo() { 
            MessageBox.Show("Hello, world, from secondary class of C#!"); 
        } 
	
	         public int calc(int returnInt, int returnInt2) { 
			 
            MessageBox.Show("Hello, world, from function of secondary class of C#!"); 
			
			local = local + 1;
			 			
			return returnInt + returnInt2 + local;
        } 
	
	  public void mysql() { 
	
	 
	      //create a MySQL connection with a query string   
		  MySqlConnection connection = new MySqlConnection("server=localhost;database=solontesting;uid=root;password="); 
 


			MySqlCommand command = connection.CreateCommand();	

			MySqlDataReader Reader;		

			command.CommandText = "select * from shares";	

			 int x;
			 
			 try 
				
				{
			
					connection.Open();
				
				}
			catch(Exception excp)
				{
					Exception myExcp = new Exception("Error connecting you to " +
                    "the my sql server. Internal error message: " + excp.Message, excp);
					
					MessageBox.Show("C# failed to connect to MySql. " + myExcp); // Display error message, Autohotkey won't display its own because ComObjError(false) is set later in the code.
					
					throw myExcp;
				
									
				
				}

			
		

			Reader = command.ExecuteReader();	
			
           string thisrow = "";

			while (Reader.Read()){	
			
				for (int i= 0;i<Reader.FieldCount;i++)		
				thisrow+=Reader.GetValue(i).ToString() + ",";		
	

				}		

		  
		  //close the connection   
		  connection.Close();
	

	
 
	MessageBox.Show("C# queried Mysql, the results are: " + thisrow); 
	 
	
	 
	
	}
	
		
 
		
    } 

)

; XML holder variables
x = <root><element var="test">Test</element></root>

x2 = <root><element var="test">XML Test 2: showing contents of a node.</element></root>

x3 = (<?xml version="1.0" encoding="UTF-8" ?>
<root>

<item>
<name>!mail</naquotme>
<description>Standard mail reply form</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>!scont</name>
<description>Subject of Contact Exception email</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>!cont</name>
<description>Body of Contact Exception email</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>mll</name>
<description>Cleans up ICT Incident report mail</description>
<scope></scope>
</item>

<item>
<name>pwmll</name>
<description>Cleans up ICT password reset mail</description>
<scope>global</scope>
</item>

<item>
<name>!regards</name>
<description>Best regards [Your name],</description> <!-- You need to escape a comma with ` Autohotkey requires that -->
<scope>Lotus Notes</scope>
</item>

<item>
<name>tel</name>
<description>telephone number</description>
<scope>global</scope>
</item>

<item>
<name>Pw</name>
<description>Password</description>
<scope></scope>
</item>

<item>
<name>pw</name>
<description>password</description>
<scope></scope>
</item>

</root>)

returnVal := 0

CLR_Start()


c#_dll_file = %A_Temp%\C#AHK\MySql.Data.dll ; Files are found at %A_Temp% because I use FileInstall at the top of the script

c#_dll_fileTwo = %A_Temp%\C#AHK\MyFunctions.dll ; Files are found at %A_Temp% because I use FileInstall at the top of the script

all_dlls = System.dll | System.Windows.Forms.dll | System.Data.dll | %c#_dll_file% | %c#_dll_fileTwo%


Windows_temp_folder = %A_Temp%\C#AHK ; Windows temp directory for storing temporary files, this is where we will store the C# exe compiled code
 
;Start a new AppDomain so we can define the base path to load assemblies from. 
CLR_StartDomain(pApp, A_Temp) ; Base path to load the DLLS with be the temp directory of Windows

CLR_CompileC#(c#, all_dlls, pApp, Windows_temp_folder . "\QueryMySql.exe") 

asm := CLR_LoadLibrary("QueryMySql.exe", pApp)

MsgBox, Hello From AutoHotKey, press control, alt and s to start the demo. Control, alt and q to quit application.

	
	
return ; End of OnExit


; Quits the application
^!q::
ExitApp
return

; continue the application

^!c::^!s ; map keys to the keys that start the application

; Start the application
^!s::
MsgBox, Hello From AutoHotKey, control, alt and s were pressed to run the following.


returnVal := runMainBody(returnVal,asm, x, x2, x3)

return

runMainBody(returnVal,asm, x, x2, x3) ; asm must be passed to a function in order to be able to 

;compile the C# code of variable c# once and be able to keep state

{



 
/* 
 
 Working with XML

*/ 

Msgbox, Working with XML

Msgbox Testing XML processing, first example: changing content.

; Testing XML processing, first example: changing content.
xpath_load(x) ; XML content can be loaded in-place directly

Msgbox Original content

Msgbox, % xpath(x, "element/text()" )

Msgbox, Changing content and showing the whole XML document

xpath(x, "element/text()", "XML Test 1: Content changed")
MsgBox, % xpath_save(x) ; show the new source without having to save it

Msgbox, Second XML example: showing content

; Second XML example: showing content

xpath_load(x2)

node = % xpath(x2, "element/text()")

MsgBox, %node%    


Msgbox Third XML example: looping through XML and showing content

; Third XML example: looping through XML and showing content

xpath_load(x3)

    
Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   hotkeys := xpath(x3, "/root/item[" . A_Index . "]/name/text()")
   description := xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   scope := xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   StringReplace, description, description, ,, `, ; Clean commas from XML, the strange code is produced by xpath in the place of comma for some reason
   
   Msgbox,%hotkeys% %description% %scope%
}

Msgbox Fourth XML example: looping through XML and changing content

; Fourth XML example: looping through XML and changing content

Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   xpath(x3, "/root/item[" . A_Index . "]/name/text()", "Dummy Text")
   xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   
} 

Msgbox, XML changed
 
 ; Save x3 XML
 
 xpath_save(x3)

Msgbox Fifth XML example: looping through XML and showing changed content

; Fifth XML example: looping through XML and showing changed content

xpath_load(x3)

    
Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   hotkeys := xpath(x3, "/root/item[" . A_Index . "]/name/text()")
   description := xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   scope := xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   StringReplace, description, description, ,, `, ; Clean commas from XML
   
   Msgbox,%hotkeys% %description% %scope%
}
 
 
/*

	Communicating from Autohotkey to C# and vice versa

*/

ComObjError(false) ; Disable COM Errors, so that only C# will produce error whenever wanted.

obj := CLR_CreateObject(asm, "Start") 

obj.MathFuct() ; equivalent to obj["MathFuct"];

obj["selectfrommysql"] ; obj[anything] should be equivalent to COM_Invoke(obj,anything). AutoHotKey_L supports COM natively

returnValue := obj["Test",10, 20] ; obj[anything] should be equivalent to COM_Invoke(obj,anything). AutoHotKey_L supports COM natively

returnVal := returnVal + returnValue

Msgbox, Value given from C#, total is kept in AutoHotKey: %returnVal% 

Msgbox, Value given from C#, total is kept in C#: %returnValue%




MsgBox, Sending arrays to C#, C# will loop through them and display their values, which are
; Sending an array to C#
arr := ComObjArray(8, 2) 
arr[0] := "string 1" 
arr[1] := "string 2" 
param := ComObjParameter(0x2008, ComObjValue(arr))

; Sending a second array to C#

arr2 := ComObjArray(3, 2) 
arr2[0] :=  3 
arr2[1] :=  4
param2 := ComObjParameter(0x2008, ComObjValue(arr2)) 

asm := CLR_CompileC#(LoadC#(), "System.dll|System.Windows.Forms.dll" ) 
obj := CLR_CreateObject(asm, "Test") 

ArrayFromC# := Object()
ArrayFromC# := obj["StringIntTest",arr,arr2]

MsgBox, C# returned arrays to Autohotkey, Autohotkey will loop through them, their values are
For value in ArrayFromC#
    MsgBox  %value%

ArrayFromC# := obj["ReturnString",arr]
For value in ArrayFromC#
    MsgBox  %value%


/*

 Dynamically building a List View from the second C# array returned to Autohotkey

*/ 

Msgbox, Dynamically building a List View from the second C# array returned to Autohotkey

; Create the ListView with two columns, Name and Size:
Gui, Add, ListView, r1 w300 +HScroll +VScroll gMyListView, Name ; Added scrollbars too

; Gather a list of file names from a folder and put them into the ListView:
For value in ArrayFromC#
    LV_Add("", value)

LV_ModifyCol()  ; Auto-size each column to fit its contents.
LV_ModifyCol(2, "Integer")  ; For sorting purposes, indicate that column 2 is an integer.

; Display the window and return. The script will be notified whenever the user double clicks a row.
Gui, Show	
	

; Speech To Text

Text := "Well done. Now you have autohotkey communicate with C Sharp .NET . Press control alt and c to continue the demo." 

SAPI := ComObjCreate("SAPI.SpVoice") 
MsgBox, 0, Rate: 0, Text To Speech 
SAPI.speak(Text) 

return returnVal

}
 

 

LoadC#() { 
c# = 
( 
using System; 
using System.Windows.Forms; 
  
public class Test 
{ 
  public int[] StringIntTest(string[] mystrings, int[] myintegers) 
  { 
     foreach(string mystring in mystrings) 
         MessageBox.Show(mystring); 
   
       foreach(int myinteger in myintegers) 
         MessageBox.Show(  Convert.ToString(myinteger) ); 
		 
		myintegers[0] = 5; 
		
		myintegers[1] = 6;
		 
		return  myintegers;
  } 
  
    public string[] ReturnString(string[] mystrings) 
  { 
		 
		mystrings[0] = "String 7"; 
		
		mystrings[1] = "String 8";
		 
		return  mystrings;
  } 
  
  
} 
) 
return c# 
} 

MyListView:
if A_GuiEvent = DoubleClick
{
    LV_GetText(RowText, A_EventInfo)  ; Get the text from the row's first field.
    ToolTip You double-clicked row number %A_EventInfo%. Text: "%RowText%"
}
return


ExitSub:

    MsgBox, 4100,Exit?, Are you sure you want to exit?, 5 ;Always on top.
	WinSet, AlwaysOnTop, toggle, Exit? 

	IfMsgBox, Yes
       {

	   
	   ExitApp


	   }
	
return


sp
  • Members
  • 52 posts
  • Last active: Jun 10 2011 02:05 PM
  • Joined: 07 May 2011
Updated code: Now the files that are extracted in %A_TEMP%\C#AHK are deleted after their loaded in the application. The folder C#AHK is also deleted.

Updated code: In this script, a splashscreen is introduced to display at the beginning of the script for a couple of seconds. A progress bar is placed on top of it, displaying Starting... . Also, the splashscreen is accompanied by a short music clip.

The splashcreen image is saved in folder images as image1.gif and the sound wav file under folder wav as wav1.wav . FileInstall though copies them to C#AHK directory under the Windows temp directory.

A clarification, besides XML, Autohotkey exchange arrays up to 8 dimensions. Of course XML can be seen as an advanced multidimensional array and there are no limits for exchanging that between Autohotkey and C#.



Updated code: Minor corrections. Now Autohotkey escapes commas from XML when it uses it with xpath.ahk, COM does not display error messages, by setting ComObjError(false), if C# .NET encounters errors (only C# can do that now, if it is programmed to do so in case of error) and DLLs files and the C# compiled from Autohotkey executable are all stored in $temp$/C#AHK where %temp% is the Windows temp directory. This is done to prevent the case where other applications may store Dlls or executable file like the one used by the application, with the same name as the Dlls/executable this application uses that may be of different version or hold different content and thus will cause problems to the application.




This is an updated script. It again introduces MyFunctions.dll and also includes xpath.ahk for XML processing. XML is useful so that you can send it to C# to do further processing and then send it back to Autohotkey for using it with its GUI or process it with the unique capabilities of AutohotKey. The Autohotkey script also populates a List View with the array of values returned from C# to Autohotkey. There are some minor additions too (and OnExit event and a hotkey maping from ^!c to ^!s).

Also, now the included ahk scripts (CRL.ahk and xpath.ahk) will have to be stored in ahk_files and Dll files are stored bin. Both directories reside where you main ahk script resides.





Updated code: This version is the same as the previous one, but it does not use the .NET Dll MyFuncions.dll . It only uses the .NET Dll Mysql.Data.dll . The reason I made this new post is for people that want to run the script, to only have to download Mysql.Data.dll for .NET from mysql.com to do that. Just save MySql.Data.dll in the folder where you will place the autohot script with the code in the post. Also, in the same folder place COM.ahk (the COM_L version for Autohotkey_L ). Remember to also install Autohotkey_L , .NET framework and MySQL and run its server (create in there a database called solontesting and make a table called shares and put data in it, also check that you have a user called root that has no password and that has rights on the database solontesting) to your PC if you haven't already do that. Once you are done, right click on the autohotscript you made, and select Run Script.

Also, to make things clearer, I shoud mention that the script compiles two C# code blocks, once in file (that is necessary if you want to include third party .NET Dlls in your application) and once in memory.






Updated code: Now you can compile the file to .exe and the compiled file will be completetly standalone. It will have in it, the third party DLLs it loads (MySql.Data.dll and MyFunctions.dll) installed in it, the .exe file. Of course it will also have in it, the CRL.ahk file too.

Note that you should have SetWorkingDir %A_Temp%
and when you load the DLLs you should also tell the autohotkey script to find them at %A_Temp%\MySql.Data.dll and %A_Temp%\MyFunctions.dll
. You should also set the CLR_StartDomain to have the AppDomain base path to A_TEMP and finally you should tell CLR_CompileC# to compile C# to exe in the path %A_Temp% .







Updated code: Now compiled C# is loaded only once and the compiled C# classes/instances keep state.







This is for Autohotkey_L

It demonstrates how to write Autohotkey and C# code in an Autohotkey script and connect and query MySql.

The script includes CRL.ahk (CRL_L version, for Autohotkey_L) and also requires Mysql driver for .NET. It also uses another dll called MyFunctions.dll (referenced with using MathFunctions; in C#). The two dll files are simply put in the directory where you will store this script and CRL.ahk. You need to have .NET framework installed in your PC too.
















;The #Directives must come before OnExit to work, #include seems to be an exception

#SingleInstance force
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
;SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

SetWorkingDir %A_Temp% ; This is the temp directory of Windows, this is where the Autohotkey application will look for the DLLs it will load and the exe compiled
;inline C# code.


#include ahk_files\CLR.ahk ; For using C# .NET from autohotkey

#Include ahk_files\xpath.ahk ; For XML

; OnExit must enclose all autoexecute code in order for OnExit to call the ExitSub if the user exits tha application
; OnExit Display pop up for confirmation

OnExit, ExitSub


; the following two files are the dlls that C# inline code uses and they will be included in the exe if the ahk script is compiled to exe.
; Note that you still need to have the two DLL files in the original DIR where your uncompiled script is, so that FileInstall will copy them to temp directory
; The compiled exe AutohotKey file will be standalone, without needing to have any files to run.

FileCreateDir, %A_Temp%\C#AHK ; Create directory to hold the Dlls and the C# compiled file, not directly in the Windows temp directory, because other programs may store the Dlls with the same names or different versions, that could cause issues to the application

FileInstall, bin\MySql.Data.dll, %A_Temp%\C#AHK\MySql.Data.dll,1

FileInstall, bin\MyFunctions.dll, %A_Temp%\C#AHK\MyFunctions.dll,1

; Wav files

FileInstall, wav\wav1.wav, %A_Temp%\C#AHK\wav1.wav,1 

; Images

FileInstall, images\image1.gif, %A_Temp%\C#AHK\image1.gif

SplashImage,  %A_Temp%\C#AHK\image1.gif, b fs18, AHK + C# Demo and more ;Always on top, but Yes/No exit dialog box if called will be on top of the splashscreen.

SoundPlay, %A_Temp%\C#AHK\wav1.wav ,wait

Loop, 300
{
Progress, %a_index%, , Starting..., AHK + C# Demo

Sleep, 1
}

Progress, Off
Sleep 1000
SplashImage, Off


c# = 
(

 

 


    using System; 

    using System.Data; 

    using System.Windows.Forms;
	
	using System.Data.SqlClient; 

	using MySql.Data.MySqlClient;
	
	using MySql.Data;
	
    using MathFunctions; // It uses the MyFunctions.dll .



// The class that allows the program to run, Note that other classes are directly accessed though.
class Start
{

Foo myfoo = new Foo();

public static int counter = 0;

  static void Main() 
   {
         
		MessageBox.Show("This program is not standalone. Please run the normal program Test.exe");
   	
		
   }
   
   public void MathFuct(){
   
   int add = AddClass.Add(125,125); // Static call to class in MyFunctions.dll
  int mul = MultiClass.Multiply(25,25); // Static call to class in MyFunctions.dll
  int fac = FactorialClass.Factorial(5); // Static call to class in MyFunctions.dll

  string str = "Addition result = " + add.ToString() + "\n"
       + "Multiplication result = " + mul.ToString() + "\n"
       + "Factorial result = " + fac.ToString();

  MessageBox.Show(str, "Call To MyFunctions.dll");
   
   
   }

   public int Test(int returnInt_, int returnInt2_)
   {
   
    
     int valueFromFooTest = myfoo.calc(returnInt_, returnInt2_);
   
     counter = counter + 1;
	 
	 return valueFromFooTest + counter;
   
   }
	
	public void selectfrommysql()
	{
		
		myfoo.mysql();
		
	}
 
   
  
   
}
 
      
 

	
    class Foo { 
	
	    public static int local = 0;
	        public  Foo() { 
            MessageBox.Show("Hello, world, from secondary class of C#!"); 
        } 
	
	         public int calc(int returnInt, int returnInt2) { 
			 
            MessageBox.Show("Hello, world, from function of secondary class of C#!"); 
			
			local = local + 1;
			 			
			return returnInt + returnInt2 + local;
        } 
	
	  public void mysql() { 
	
	 
	      //create a MySQL connection with a query string   
		  MySqlConnection connection = new MySqlConnection("server=localhost;database=solontesting;uid=root;password="); 
 


			MySqlCommand command = connection.CreateCommand();	

			MySqlDataReader Reader;		

			command.CommandText = "select * from shares";	

			 int x;
			 
			 try 
				
				{
			
					connection.Open();
				
				}
			catch(Exception excp)
				{
					Exception myExcp = new Exception("Error connecting you to " +
                    "the my sql server. Internal error message: " + excp.Message, excp);
					
					MessageBox.Show("C# failed to connect to MySql. " + myExcp); // Display error message, Autohotkey won't display its own because ComObjError(false) is set later in the code.
					
					throw myExcp;
				
									
				
				}

			
		

			Reader = command.ExecuteReader();	
			
           string thisrow = "";

			while (Reader.Read()){	
			
				for (int i= 0;i<Reader.FieldCount;i++)		
				thisrow+=Reader.GetValue(i).ToString() + ",";		
	

				}		

		  
		  //close the connection   
		  connection.Close();
	

	
 
	MessageBox.Show("C# queried Mysql, the results are: " + thisrow); 
	 
	
	 
	
	}
	
		
 
		
    } 

)

; XML holder variables
x = <root><element var="test">Test</element></root>

x2 = <root><element var="test">XML Test 2: showing contents of a node.</element></root>

x3 = (<?xml version="1.0" encoding="UTF-8" ?>
<root>

<item>
<name>!mail</naquotme>
<description>Standard mail reply form</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>!scont</name>
<description>Subject of Contact Exception email</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>!cont</name>
<description>Body of Contact Exception email</description>
<scope>Lotus Notes</scope>
</item>

<item>
<name>mll</name>
<description>Cleans up ICT Incident report mail</description>
<scope></scope>
</item>

<item>
<name>pwmll</name>
<description>Cleans up ICT password reset mail</description>
<scope>global</scope>
</item>

<item>
<name>!regards</name>
<description>Best regards [Your name],</description> <!-- You need to escape a comma with ` Autohotkey requires that -->
<scope>Lotus Notes</scope>
</item>

<item>
<name>tel</name>
<description>telephone number</description>
<scope>global</scope>
</item>

<item>
<name>Pw</name>
<description>Password</description>
<scope></scope>
</item>

<item>
<name>pw</name>
<description>password</description>
<scope></scope>
</item>

</root>)

returnVal := 0

CLR_Start()


c#_dll_file = %A_Temp%\C#AHK\MySql.Data.dll ; Files are found at %A_Temp% because I use FileInstall at the top of the script

c#_dll_fileTwo = %A_Temp%\C#AHK\MyFunctions.dll ; Files are found at %A_Temp% because I use FileInstall at the top of the script

all_dlls = System.dll | System.Windows.Forms.dll | System.Data.dll | %c#_dll_file% | %c#_dll_fileTwo%


Windows_temp_folder = %A_Temp%\C#AHK ; Windows temp directory for storing temporary files, this is where we will store the C# exe compiled code
 
;Start a new AppDomain so we can define the base path to load assemblies from. 
CLR_StartDomain(pApp, A_Temp) ; Base path to load the DLLS with be the temp directory of Windows

CLR_CompileC#(c#, all_dlls, pApp, Windows_temp_folder . "\QueryMySql.exe") 

asm := CLR_LoadLibrary("QueryMySql.exe", pApp)

; Delete temp files extracted from compiled script, there are now in memory and there are not needed.

FileDelete, %A_Temp%\C#AHK\MySql.Data.dll

FileDelete, %A_Temp%\C#AHK\MyFunctions.dll

FileDelete, %A_Temp%\C#AHK\wav1.wav

FileDelete, %A_Temp%\C#AHK\image1.gif

FileDelete, %A_Temp%\C#AHK\QueryMySql.exe

FileDelete, %A_Temp%\C#AHK\QueryMySql.pdb ; Debugging file, created by the .exe compilation of the C# code


FileRemoveDir %A_Temp%\C#AHK


MsgBox, Hello From AutoHotKey, press control, alt and s to start the demo. Control, alt and q to quit application.

	
	
return ; End of OnExit


; Quits the application
^!q::
ExitApp
return

; continue the application

^!c::^!s ; map keys to the keys that start the application

; Start the application
^!s::
MsgBox, Hello From AutoHotKey, control, alt and s were pressed to run the following.


returnVal := runMainBody(returnVal,asm, x, x2, x3)

return

runMainBody(returnVal,asm, x, x2, x3) ; asm must be passed to a function in order to be able to 

;compile the C# code of variable c# once and be able to keep state

{



 
/* 
 
 Working with XML

*/ 

Msgbox, Working with XML

Msgbox Testing XML processing, first example: changing content.

; Testing XML processing, first example: changing content.
xpath_load(x) ; XML content can be loaded in-place directly

Msgbox Original content

Msgbox, % xpath(x, "element/text()" )

Msgbox, Changing content and showing the whole XML document

xpath(x, "element/text()", "XML Test 1: Content changed")
MsgBox, % xpath_save(x) ; show the new source without having to save it

Msgbox, Second XML example: showing content

; Second XML example: showing content

xpath_load(x2)

node = % xpath(x2, "element/text()")

MsgBox, %node%    


Msgbox Third XML example: looping through XML and showing content

; Third XML example: looping through XML and showing content

xpath_load(x3)

    
Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   hotkeys := xpath(x3, "/root/item[" . A_Index . "]/name/text()")
   description := xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   scope := xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   StringReplace, description, description, ,, `, ; Clean commas from XML, the strange code is produced by xpath in the place of comma for some reason
   
   Msgbox,%hotkeys% %description% %scope%
}

Msgbox Fourth XML example: looping through XML and changing content

; Fourth XML example: looping through XML and changing content

Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   xpath(x3, "/root/item[" . A_Index . "]/name/text()", "Dummy Text")
   xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   
} 

Msgbox, XML changed
 
 ; Save x3 XML
 
 xpath_save(x3)

Msgbox Fifth XML example: looping through XML and showing changed content

; Fifth XML example: looping through XML and showing changed content

xpath_load(x3)

    
Loop
{
   If xpath(x3, "/root/item[" . A_Index . "]") = ""
      Break
   hotkeys := xpath(x3, "/root/item[" . A_Index . "]/name/text()")
   description := xpath(x3, "/root/item[" . A_Index . "]/description/text()")
   scope := xpath(x3, "/root/item[" . A_Index . "]/scope/text()")
   
   StringReplace, description, description, ,, `, ; Clean commas from XML
   
   Msgbox,%hotkeys% %description% %scope%
}
 
 
/*

	Communicating from Autohotkey to C# and vice versa

*/

ComObjError(false) ; Disable COM Errors, so that only C# will produce error whenever wanted.

obj := CLR_CreateObject(asm, "Start") 

obj.MathFuct() ; equivalent to obj["MathFuct"];

obj["selectfrommysql"] ; obj[anything] should be equivalent to COM_Invoke(obj,anything). AutoHotKey_L supports COM natively

returnValue := obj["Test",10, 20] ; obj[anything] should be equivalent to COM_Invoke(obj,anything). AutoHotKey_L supports COM natively

returnVal := returnVal + returnValue

Msgbox, Value given from C#, total is kept in AutoHotKey: %returnVal% 

Msgbox, Value given from C#, total is kept in C#: %returnValue%




MsgBox, Sending arrays to C#, C# will loop through them and display their values, which are
; Sending an array to C#
arr := ComObjArray(8, 2) 
arr[0] := "string 1" 
arr[1] := "string 2" 
param := ComObjParameter(0x2008, ComObjValue(arr))

; Sending a second array to C#

arr2 := ComObjArray(3, 2) 
arr2[0] :=  3 
arr2[1] :=  4
param2 := ComObjParameter(0x2008, ComObjValue(arr2)) 

asm := CLR_CompileC#(LoadC#(), "System.dll|System.Windows.Forms.dll" ) 
obj := CLR_CreateObject(asm, "Test") 

ArrayFromC# := Object()
ArrayFromC# := obj["StringIntTest",arr,arr2]

MsgBox, C# returned arrays to Autohotkey, Autohotkey will loop through them, their values are
For value in ArrayFromC#
    MsgBox  %value%

ArrayFromC# := obj["ReturnString",arr]
For value in ArrayFromC#
    MsgBox  %value%


/*

 Dynamically building a List View from the second C# array returned to Autohotkey

*/ 

Msgbox, Dynamically building a List View from the second C# array returned to Autohotkey

; Create the ListView with two columns, Name and Size:
Gui, Add, ListView, r1 w300 +HScroll +VScroll gMyListView, Name ; Added scrollbars too

; Gather a list of file names from a folder and put them into the ListView:
For value in ArrayFromC#
    LV_Add("", value)

LV_ModifyCol()  ; Auto-size each column to fit its contents.
LV_ModifyCol(2, "Integer")  ; For sorting purposes, indicate that column 2 is an integer.

; Display the window and return. The script will be notified whenever the user double clicks a row.
Gui, Show	
	

; Speech To Text

Text := "Well done. Now you have autohotkey communicate with C Sharp .NET . Press control alt and c to continue the demo." 

SAPI := ComObjCreate("SAPI.SpVoice") 
MsgBox, 0, Rate: 0, Text To Speech 
SAPI.speak(Text) 

return returnVal

}
 

 

LoadC#() { 
c# = 
( 
using System; 
using System.Windows.Forms; 
  
public class Test 
{ 
  public int[] StringIntTest(string[] mystrings, int[] myintegers) 
  { 
     foreach(string mystring in mystrings) 
         MessageBox.Show(mystring); 
   
       foreach(int myinteger in myintegers) 
         MessageBox.Show(  Convert.ToString(myinteger) ); 
		 
		myintegers[0] = 5; 
		
		myintegers[1] = 6;
		 
		return  myintegers;
  } 
  
    public string[] ReturnString(string[] mystrings) 
  { 
		 
		mystrings[0] = "String 7"; 
		
		mystrings[1] = "String 8";
		 
		return  mystrings;
  } 
  
  
} 
) 
return c# 
} 

MyListView:
if A_GuiEvent = DoubleClick
{
    LV_GetText(RowText, A_EventInfo)  ; Get the text from the row's first field.
    ToolTip You double-clicked row number %A_EventInfo%. Text: "%RowText%"
}
return


ExitSub:

    MsgBox, 4100,Exit?, Are you sure you want to exit?, 5 ;Always on top.
	WinSet, AlwaysOnTop, toggle, Exit? 

	IfMsgBox, Yes
       {

	   
	   ExitApp


	   }
	
return


sp
  • Members
  • 52 posts
  • Last active: Jun 10 2011 02:05 PM
  • Joined: 07 May 2011
Actually my previous post had a couple of mistakes.

First SetWorkingDir has to be set to %temp%\C#AHK

Secondly the FileDelete statements must be removed because, the files are not put in memory after all.

I will post my code online, together with non code files, probably in sourceforge, so stay tuned.

sp
  • Members
  • 52 posts
  • Last active: Jun 10 2011 02:05 PM
  • Joined: 07 May 2011
Here is how to add Java Support in C#/ AutoHotKey (AutoHotKey_L) interop:

This is the first part of the code you will need, basically you compile your C# code and add references to IKVM ( Java in .NET ):

CLR_Start()

; Compiling Java C# Bridge that allow to write Java code inside C#

c#_dll_file := A_ScriptDir "\LanguageFiles\JavaC#\ICSharpCode.SharpZipLib.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.AWT.WinForms.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Beans.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Charsets.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Corba.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Core.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Jdbc.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Management.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Media.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Misc.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Naming.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Remoting.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Security.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.SwingAWT.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Text.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Tools.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.Util.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.XML.API.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.XML.Bind.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.XML.Crypto.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.XML.Parse.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.XML.Transform.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.XML.WebServices.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.OpenJDK.XML.XPath.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.Reflection.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.Runtime.dll |"
c#_dll_file .= A_ScriptDir "\LanguageFiles\JavaC#\IKVM.Runtime.JNI.dll"



all_dlls = System.dll | System.Windows.Forms.dll | System.Data.dll | %c#_dll_file% 


Windows_temp_folder = %A_ScriptDir%\LanguageFiles\JavaC# ; Windows temp directory for storing temporary files, this is where we will store the C# exe compiled code
 
;Start a new AppDomain so we can define the base path to load assemblies from. 

CLR_StartDomain(pApp, A_ScriptDir) ; Base path to load the DLLS with be the temp directory of Windows


; Compile the C# code of variable c# once and be able to keep state.
CLR_CompileC#(LoadJavaC#(), all_dlls, pApp, Windows_temp_folder . "\JavaC#.exe")  

while NOT FileExist(A_ScriptDir "\LanguageFiles\JavaC#\JavaC#.exe") ; wait for file to exist, before loading it
    sleep 100


asmJava := CLR_LoadLibrary("LanguageFiles\JavaC#\JavaC#.exe", pApp)

objJava := CLR_CreateObject(asmJava, "Start")

And this is the second part:

; C# Java with Java Classes(libraries)(IKVM).

^!+5::

MsgBox, C# Java

	runJavaC#(objJava)

return


runJavaC#(objJava)
{

returnJava1 := objJava.CallJava(5)
	
	MsgBox, %returnJava1%

}


LoadJavaC#()
{
c# =
(

using System; 
using System.Windows.Forms; 

// Java class imports.

using java.util; // For Java HashSet

using java.lang; // For Java arrays
 
public class Start
{ 

  static void Main() 
   {
         
		MessageBox.Show("This program is not standalone. Please run the normal program");
   	
		
   }

  public int CallJava(int java_parameter) 
  { 

		/*
		
			C# to Java to C#	
		
		*/
		
		
	// Create an instance of a .NET string
	string str = "abc|def|ghi|jkl";

     // Tokenize it w/ an instance of the java.util.StringTokenizer
	StringTokenizer Jst = new StringTokenizer( str, "|" );

        // Create an instance of the java.util.HashSet
	Set Jhs = new HashSet();

        // Iterate over the tokens
	while( Jst.hasMoreTokens() ) 
		{
            
			var str2 = Jst.nextToken();
			
			string temp = str2.ToUpper();		
			
			Jhs.add( temp );
			
        }

		
		// Traverse HashSet and capture text in C# string variable
		
		var str3 = "";
		
	  // Retrieve an iterator to the hashset:
      Iterator iter = Jhs.iterator();
 
      // Extract elements from iterator.
      // Note that the elements may not follow the order in which they
      // are added to HashSet.
      while(iter.hasNext()) 
		{
         
			str3 += iter.next();
         
		}

		
		
       // Display data from Java.	
	  
	
		MessageBox.Show( str3 );
 
  
		return java_parameter;
	
  }
     
		 
		 
  } 
  
  
 
)
return c#
}


sp
  • Members
  • 52 posts
  • Last active: Jun 10 2011 02:05 PM
  • Joined: 07 May 2011
This code includes an extra example of running Java and C# in AutoHotKey_L. This time a URL is read and its contents are displayed line by line (the secret for programming in Java and C# at the same time is to use C# strings and not Java strings):

; C# Java with Java Classes(libraries)(IKVM).

^!+5::

MsgBox, C# Java

	runJavaC#(objJava)

return


runJavaC#(objJava)
{

returnJava1 := objJava.CallJava(5)
	
	MsgBox, %returnJava1%

}


LoadJavaC#()
{
c# =
(

using System; 
using System.Windows.Forms; 

// Java class imports.

using java.util;  //For StringTokenizer, HashSet, Iterator.

using java.net; // For URL

using java.io; // For InputStream, DataInputStream, BufferedInputStream.


public class Start
{ 

  static void Main() 
   {
         
		MessageBox.Show("This program is not standalone. Please run the normal program");
   	
		
   }

  public int CallJava(int java_parameter) 
  { 

		/*
		
			C# to Java to C#	
		
		*/
		
		
	// Create an instance of a .NET string
	string str = "abc|def|ghi|jkl";

     // Tokenize it w/ an instance of the java.util.StringTokenizer
	StringTokenizer Jst = new StringTokenizer( str, "|" );

        // Create an instance of the java.util.HashSet
	Set Jhs = new HashSet();

        // Iterate over the tokens
	while( Jst.hasMoreTokens() ) 
		{
            
			var str2 = Jst.nextToken();
			
			string temp = str2.ToUpper();		
			
			Jhs.add( temp );
			
        }

		
		// Traverse HashSet and capture text in C# string variable
		
		var str3 = "";
		
	  // Retrieve an iterator to the hashset:
      Iterator iter = Jhs.iterator();
 
      // Extract elements from iterator.
      // Note that the elements may not follow the order in which they
      // are added to HashSet.
      while(iter.hasNext()) 
		{
         
			str3 += iter.next();
         
		}

		
		
       // Display data from Java.	
	  
	
		MessageBox.Show( str3 );
 
		/*
		
			Reading a URL and displaying contents.
			
			
		*/

      URL u = new URL("http://www.yahoo.com");
      InputStream is_ = null;
      DataInputStream dis;
      
	  string s;
	  
	     
		
		 is_ = u.openStream(); 
		
		dis = new DataInputStream(new BufferedInputStream(is_));
		
		 while ((s = dis.readLine()) != null) {
           MessageBox.Show( s );
         }
		
  
		return java_parameter;
	
  }
     
		 
		 
  } 
  
  
 
)
return c#
}


sp
  • Members
  • 52 posts
  • Last active: Jun 10 2011 02:05 PM
  • Joined: 07 May 2011
ABCL is a full implementation of Common Lisp (including its libraries) for .NET (actually there is a version for Java too).

Download the archive with ABCL for .NET from the net.

ABCL uses some IKVM libraries, but you should reference the libraries provided in its archive, not the latest IKVM libraries.

My example uses SetWorkingDir %A_Temp%

This code FileInstall's the Dlls of ABCL in the temp directory.

Here is the code to include the Full Common Lisp in C# in AHK:


; For DLLs and other files
FileCreateDir, %A_Temp%\SPDEMO

FileCreateDir, %A_Temp%\SPDEMO\LanguageFiles

FileCreateDir, %A_Temp%\SPDEMO\LanguageFiles\LISPC#


; Installing ABCL Common Lisp to JavaC#
FileInstall, LanguageFiles\LISPC#\ABCL.Net.dll,                     %A_Temp%\SPDEMO\LanguageFiles\LISPC#\ABCL.Net.dll
FileInstall, LanguageFiles\LISPC#\IKVM.OpenJDK.Core.dll,            %A_Temp%\SPDEMO\LanguageFiles\LISPC#\IKVM.OpenJDK.Core.dll
FileInstall, LanguageFiles\LISPC#\IKVM.OpenJDK.Security.dll,        %A_Temp%\SPDEMO\LanguageFiles\LISPC#\IKVM.OpenJDK.Security.dll
FileInstall, LanguageFiles\LISPC#\IKVM.OpenJDK.Util.dll,            %A_Temp%\SPDEMO\LanguageFiles\LISPC#\IKVM.OpenJDK.Util.dll
FileInstall, LanguageFiles\LISPC#\IKVM.Runtime.dll,                 %A_Temp%\SPDEMO\LanguageFiles\LISPC#\IKVM.Runtime.dll


returnVal := 0

CLR_Start()

; Compiling Lisp C# Bridge that allows to write Lisp code inside C#


c#_dll_file := A_Temp "\SPDEMO\LanguageFiles\LISPC#\ABCL.Net.dll |"
c#_dll_file .= A_Temp "\SPDEMO\LanguageFiles\LISPC#\IKVM.OpenJDK.Core.dll |"
c#_dll_file .= A_Temp "\SPDEMO\LanguageFiles\LISPC#\IKVM.OpenJDK.Security.dll |"
c#_dll_file .= A_Temp "\SPDEMO\LanguageFiles\LISPC#\IKVM.OpenJDK.Util.dll |"
c#_dll_file .= A_Temp "\SPDEMO\LanguageFiles\LISPC#\IKVM.Runtime.dll"


all_dlls = System.dll | System.Windows.Forms.dll | System.Data.dll | %c#_dll_file% 


Windows_temp_folder = %A_Temp%\SPDEMO\LanguageFiles\LISPC# ; Windows temp directory for storing temporary files, this is where we will store the C# exe compiled code
 
;Start a new AppDomain so we can define the base path to load assemblies from. 

CLR_StartDomain(pApp, A_Temp) ; Base path to load the DLLS with be the temp directory of Windows


; Compile the C# code of variable c# once and be able to keep state.
CLR_CompileC#(LoadLispC#(), all_dlls, pApp, Windows_temp_folder . "\LISPC#.exe")  

while NOT FileExist(A_Temp "\SPDEMO\LanguageFiles\LISPC#\LISPC#.exe") ; wait for file to exist, before loading it
    sleep 100


asmLisp := CLR_LoadLibrary("SPDEMO\LanguageFiles\LISPC#\LISPC#.exe", pApp)

objLisp := CLR_CreateObject(asmLisp, "Start")


; Start the Common Lisp demo.
^!+0::

MsgBox Common Lisp C# Demo.


	runLispC#(objLisp)

return


runLispC#(objLisp)
{

returnLisp1 := objLisp.LispStringTest(5)
	
	MsgBox, %returnLisp1%


	
}


LoadLispC#()
{
c# =
(

using System; 
using System.Windows.Forms; 
using System.Threading; // For Thread Start



// ABCL Common Lisp 

using org.armedbear.lisp;

public class Start
{ 

  static void Main() 
   {
         
		MessageBox.Show("This program is not standalone. Please run the normal program");
   	
		
   }

  public int LispStringTest(int lisp_parameter) 
  { 

  
  		/*
		
			C# to Lisp to C#	
		
		*/
  
  
  
var result  = Lisp.eval(Lisp.readObjectFromString("(+ 1 1)"));



MessageBox.Show("result = " +  result.writeToString() );  
  
 
string csharpString = "(+ 2 1)";
 
LispObject lispObj = Lisp.readObjectFromString(csharpString);

LispObject result2 = Lisp.eval(lispObj);
 
MessageBox.Show("result = " +  result2.writeToString() ); 
		
	    return lisp_parameter;
		
		}
		

     
		 
		 
  } 
  
  
 
)
return c#
}


tonne
  • Members
  • 1654 posts
  • Last active: May 06 2014 06:22 PM
  • Joined: 06 Jun 2006
xkcd: Lisp Cycles

ProgrammerPaul
  • Members
  • 75 posts
  • Last active: Oct 05 2017 01:14 PM
  • Joined: 28 May 2009
I had trouble a while ago but got it working. This sample script is failing on my machines again. I think there may have been some kind of update to windows and/or the .net framework.
#include clr.ahk
#include com.ahk
			vb =
			(
			    Imports System.Windows.Forms
			    Class Foo
				Public Sub Test()
				microsoft.visualbasic.msgbox("this is nuts!")
				    MessageBox.Show("Hello, world, from VB!")
				End Sub
			    End Class
			)

			CLR_Start()

			asm := CLR_CompileVB(vb, "System.dll | System.Windows.Forms.dll")
			obj := CLR_CreateObject(asm, "Foo")
			COM_Invoke(obj, "Test")
			COM_Release(obj), COM_Release(asm)

I get this error:

---------------------------
dotnetsample.ahk
---------------------------
Error in #include file "C:\temp\Paul\Framework\com.ahk":
0x80020006 - Unknown name.


Specifically: prm_

Line#
558: {
559: Return,IsObject(prm)?prm:Object("typ_",typ,"prm_",prm,"nam_",nam)
560: }
563: {
565: Return,IsObject(obj)?obj:Object("prm_",obj,"typ_",vt,"base",base?base:base:=Object("__Delete","COM_Invoke","__Call","COM_Invoke","__Get","COM_Invoke","__Set","COM_InvokeSet","base",Object("__Delete","COM_Term")))
566: }
569: {
---> 570: Return,IsObject(obj)?obj.prm_:obj
571: }
003: MsgBox,IsObject(CLR_LoadLibrary("System"))
004: vb = Imports System.Windows.Forms
Class Foo
Public Sub Test()
microsoft.visualbasic.msgbox("this is nuts!")
MessageBox.Show("Hello, world, from VB!")
End Sub
End Class
015: CLR_Start()
017: asm := CLR_CompileVB(vb, "System.dll | System.Windows.Forms.dll")
018: obj := CLR_CreateObject(asm, "Foo")
019: COM_Invoke(obj, "Test")

Continue running the script?
---------------------------
Yes No
---------------------------

I am experiencing difficulties on Windows Vista, 7 and 2008 R2. Does anyone have any suggestions? I'm running this test all on the C drive so security should not be a concern.
As per previous diagnostic attempts, I verified that this pops up a 1
MsgBox % IsObject(CLR_LoadLibrary("System"))

Thanks so much for your help! This functionality has become an integral part of my day to day usage of AHK. I had forgotten how much it was doing for me!

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
CLR_L uses the built-in COM support, not COM.ahk. Replace the last two lines with:
obj.Test()
obj := "", asm := "" ; Not strictly necessary.


ProgrammerPaul
  • Members
  • 75 posts
  • Last active: Oct 05 2017 01:14 PM
  • Joined: 28 May 2009
That seems to be doing the trick! What benefit does changing COM_Release to var:="" offer (as opposed to removing the calls)? Does it just free up a bit of memory?

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
It depends on the object, which may hold other resources such as file handles, network connections, etc. Generally it's better to put your code inside a function, use local variables and let them be freed automatically.

Wade Hatler
  • Members
  • 40 posts
  • Last active: Nov 06 2014 10:46 PM
  • Joined: 28 Sep 2004
Took me a while to figure out to get this working with AutoHotkey_L since most of the examples are for classic, so I thought I'd post the first example from back on the first page to _L.

c# =
(
    using System.Windows.Forms;
    class Foo {
        public void Test() {
            MessageBox.Show("Hello, world, from C#!");
        }
    }
)
vb =
(
    Imports System.Windows.Forms
    Class Foo
        Public Sub Test()
            MessageBox.Show("Hello, world, from VB!")
        End Sub
    End Class
)

    CLR_Start()

    ; Compile and execute C# code
    asm := CLR_CompileC#(c#, "System.dll | System.Windows.Forms.dll")
    obj := CLR_CreateObject(asm, "Foo")
    obj.Test()

    obj=
    ; Note: This doesn't unload the Assembly itself, just frees the Assembly object.
    asm=

    ; Compile and execute VB code
    asm := CLR_CompileVB(vb, "System.dll | System.Windows.Forms.dll")
    obj := CLR_CreateObject(asm, "Foo")
    obj.Test()

    ; Create a .NET Form all in AHK.  Haven't figured out how to add controls yet, but I'd probably do that in C# anyway
    asm := CLR_LoadLibrary("System.Windows.Forms")
    frm := CLR_CreateObject(asm, "System.Windows.Forms.Form")
    frm.StartPosition := 1 ; FormStartPosition.CenterScreen
    frm.Text := "Hello WinForms"
    frm.ShowDialog()
    ExitApp


panofish
  • Members
  • 179 posts
  • Last active: Apr 24 2014 03:24 PM
  • Joined: 05 Feb 2007
Does anyone have the CLR_L library?