Embedding Python in AHK

Get help with using AutoHotkey and its commands and hotkeys
XeroByte
Posts: 26
Joined: 17 Sep 2014, 01:30

Embedding Python in AHK

18 May 2015, 09:14

I'm trying to embed some python code into an ahk script, and get it to run the python code.

Please can somebody shed some light on why the following autohotkey code to run a defined string of python code using my python installation isn't working.

The dll file is definitely at that location, if I msgbox the results of the dllcalls i get (in order): 503316480 , 68762920 , -1 , 0 . The second number changes every time, but the others are always the same

My end goal is to create a hotkey that will copy any selected text and run it as a python script. Once this part is working, the rest will fit into place.

Code: Select all

py = 
(  
import ctypes
ctypes.windll.user32.MessageBoxW(0, "Your text", "Your title", 1)
) 

DllCall("LoadLibrary", "str", A_WinDir "\SYSTEM32\python33.dll") 
DllCall(A_WinDir "\SYSTEM32\python33.dll\Py_Initialize", "Cdecl") 
DllCall(A_WinDir "\SYSTEM32\python33.dll\PyRun_SimpleString", "str",py, "Cdecl")
DllCall(A_WinDir "\SYSTEM32\python33.dll\Py_Finalize", "Cdecl")
Thanks all!
guest3456
Posts: 2794
Joined: 09 Oct 2013, 10:31

Re: Embedding Python in AHK

18 May 2015, 16:33

you sure your python code is correct?

https://docs.python.org/2/c-api/veryhigh.html wrote: int PyRun_SimpleString(const char *command)
This is a simplified interface to PyRun_SimpleStringFlags() below, leaving the PyCompilerFlags* argument set to NULL.

int PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
Executes the Python source code from command in the __main__ module according to the flags argument. If __main__ does not already exist, it is created. Returns 0 on success or -1 if an exception was raised. If there was an error, there is no way to get the exception information. For the meaning of flags, see below.

Note that if an otherwise unhandled SystemExit is raised, this function will not return -1, but exit the process, as long as Py_InspectFlag is not set.
otherwise maybe try changing the DllCall param from Str to something else, such as AStr or "Ptr", &py

http://ahkscript.org/docs/Compat.htm#DllCall

XeroByte
Posts: 26
Joined: 17 Sep 2014, 01:30

Re: Embedding Python in AHK

18 May 2015, 17:58

guest3456 wrote:you sure your python code is correct?
otherwise maybe try changing the DllCall param from Str to something else, such as AStr or "Ptr", &py
http://ahkscript.org/docs/Compat.htm#DllCall
Excellent!!! Thank you!!!!! Changing Str to AStr did the trick!

New Code:

Code: Select all

py = 
(  
import ctypes
ctypes.windll.user32.MessageBoxW(0, "Your text", "Your title", 1)
) 
 
DllCall("LoadLibrary", "str", A_WinDir "\SYSTEM32\python33.dll") 
DllCall(A_WinDir "\SYSTEM32\python33.dll\Py_Initialize", "Cdecl") 
DllCall(A_WinDir "\SYSTEM32\python33.dll\PyRun_SimpleString", "Astr",py, "Cdecl")
DllCall(A_WinDir "\SYSTEM32\python33.dll\Py_Finalize", "Cdecl")
XeroByte
Posts: 26
Joined: 17 Sep 2014, 01:30

Re: Embedding Python in AHK

18 May 2015, 18:35

If anybody is interested, here is my final code that will run python embedded in AHK or selected python code via a hotkey:

Code: Select all

;Example 1 - Run python code that is embedded as a string in autohotkey
py = 
(  
import ctypes
ctypes.windll.user32.MessageBoxW(0, "Brought to you by the knights who say ni", "Python Message Box", 1)
)  
RunPython(py)
return

;Example 2 - Run any selected python code with a hotkey (highlight some valid python code and then hit Ctrl + Win + S)
^#S:: RunPython()

RunPython(pyStr:=""){ ; Requires the Selection() function included below
	PythonDll := A_WinDir "\SYSTEM32\python33.dll" ; Make sure that this is the python version that you have installed
	finalPyStr := (pyStr="") ? Selection() : pyStr ; if a string has been passed into this function then use that as the python code, otherwise use the currently selected text using my custom Selection() function
	if(StrLen(finalPyStr) > 0){ ; Only do the following if there is some python code to run
		DllCall("LoadLibrary", "Str", PythonDll)
		DllCall(PythonDll "\Py_Initialize", "Cdecl")
		DllCall(PythonDll "\PyRun_SimpleString", "AStr", finalPyStr)
		DllCall(PythonDll "\Py_Finalize", "Cdecl")
	}
	return	
}

;the below Selection() function is a dependency for RunPython() so that it can retrieve the contents of highlighted text
Selection(WaitTime:=0.5, ByRef TempClipSaved:="NotPassed"){
	;returns the selected text. Optionally pass in the 'wait time' which prevents the action timing out for the defined amount of time (seconds). 
	;Optionally pass in a byref variable to TempClipSaved to hold the old clipboardAll data - to rewrite later. This will also stop the function from rewriting the original clipboard
	;Alternatively simply change the TempClipSaved value to any arbitrary string to avoid rewriting the original clipboard
	bolRewriteClip := (TempClipSaved="NotPassed") ? 1 : 0
	TempClipSaved := ClipboardAll
	Clipboard=
	Send, ^c
	ClipWait,%WaitTime%
	TempSelection := (ErrorLevel)? "" : Clipboard
	if(bolRewriteClip)
		Clipboard := TempClipSaved
	return, TempSelection
}

ameyrick
Posts: 119
Joined: 20 Apr 2014, 18:12

Re: Embedding Python in AHK

19 May 2015, 17:47

Hi thanks for this!
I've added a function to change which python version to use.
It's interesting to note that your script will produce a popup in Japanese text when running under python27.dll
python in ahk.png

Code: Select all

#SingleInstance force
PythonDll := PyVer(27) ;// Choose the Python version to use.

PyVer(v:="")
{
	if v
		if fileExist(A_WinDir "\SYSTEM32\python" v ".dll")
			return A_WinDir "\SYSTEM32\python" v ".dll"

	if fileExist(A_WinDir "\SYSTEM32\python34.dll")
		return A_WinDir "\SYSTEM32\python34.dll"
	
	if fileExist(A_WinDir "\SYSTEM32\python33.dll")
		return A_WinDir "\SYSTEM32\python33.dll"
	
	if fileExist(A_WinDir "\SYSTEM32\python27.dll")
		return A_WinDir "\SYSTEM32\python27.dll"
	
	msgbox, Python not found!
	return 0
}


;Example 1 - Run python code that is embedded as a string in autohotkey
py = 
(  
import ctypes
ctypes.windll.user32.MessageBoxW(0, "Brought to you by the knights who say ni", "Python Message Box", 1)
)  
RunPython(py)
return

;Example 2 - Run any selected python code with a hotkey (highlight some valid python code and then hit Ctrl + Win + S)
^#S:: RunPython()

RunPython(pyStr:=""){ ; Requires the Selection() function included below
	Global PythonDll
	if ( PythonDll == 0 )
		return
	finalPyStr := (pyStr="") ? Selection() : pyStr ; if a string has been passed into this function then use that as the python code, otherwise use the currently selected text using my custom Selection() function
	if(StrLen(finalPyStr) > 0){ ; Only do the following if there is some python code to run
		DllCall("LoadLibrary", "Str", PythonDll)
		DllCall(PythonDll "\Py_Initialize", "Cdecl")
		DllCall(PythonDll "\PyRun_SimpleString", "AStr", finalPyStr)
		DllCall(PythonDll "\Py_Finalize", "Cdecl")
	}
	return
}

;the below Selection() function is a dependency for RunPython() so that it can retrieve the contents of highlighted text
Selection(WaitTime:=0.5, ByRef TempClipSaved:="NotPassed"){
	;returns the selected text. Optionally pass in the 'wait time' which prevents the action timing out for the defined amount of time (seconds). 
	;Optionally pass in a byref variable to TempClipSaved to hold the old clipboardAll data - to rewrite later. This will also stop the function from rewriting the original clipboard
	;Alternatively simply change the TempClipSaved value to any arbitrary string to avoid rewriting the original clipboard
	bolRewriteClip := (TempClipSaved="NotPassed") ? 1 : 0
	TempClipSaved := ClipboardAll
	Clipboard=
	Send, ^c
	ClipWait,%WaitTime%
	TempSelection := (ErrorLevel)? "" : Clipboard
	if(bolRewriteClip)
		Clipboard := TempClipSaved
	return, TempSelection
}

User avatar
empardopo
Posts: 336
Joined: 06 Oct 2013, 12:50
Location: Spain
Contact:

Re: Embedding Python in AHK

20 May 2015, 04:55

Interesting!I must learn Python, java, .... :-)
Everything is possible!
XeroByte
Posts: 26
Joined: 17 Sep 2014, 01:30

Re: Embedding Python in AHK

25 May 2015, 06:12

Hi Ameyrick, Thanks for your comments :)

I liked your idea regarding choosing the Python version, I wrote a slightly different version an built it into the RunPython() function as a second argument. Yours is possibly faster/more direct, but I thought it might be a bit neater to build it in, and allow for an auto-select of more python versions.

Code: Select all

;Example 1 - Run python code that is embedded as a string in autohotkey
py = 
(  
import ctypes
ctypes.windll.user32.MessageBoxW(0, "Brought to you by the knights who say ni", "Python Message Box", 1)
)  
RunPython(py)
; OR, if you would like to specifically choose Python version 3.3
RunPython(py,"33")
return
 
;Example 2 - Run any selected python code with a hotkey (highlight some valid python code and then hit Ctrl + Win + S)
^#S:: RunPython()
 
RunPython(pyStr:="", PyVer:=""){ ; Requires the Selection() function included below
	static PythonDll ; Set this Var as static so that repeated calls don't need to go through the PyVer discovery loop
	if PyVer ; If PyVer has been Specified
	{
		if fileExist(A_WinDir "\SYSTEM32\python" PyVer ".dll")
			PythonDll := A_WinDir "\SYSTEM32\python" PyVer ".dll"
		else
			return -1
	}
	if not fileExist(PythonDll)
	{
		Loop, 50 ; This is the PyVer discovery loop - Choose the highest version of Python available (up to 50)
		{
			if fileExist(A_WinDir "\SYSTEM32\python" (51 - A_Index) ".dll") ; This loop starts looking for python version 50 and works its way back to 1 (yes i know most of these don't even exist)
			{
				PythonDll := A_WinDir "\SYSTEM32\python" (51 - A_Index) ".dll"
				break
			}
			if(A_Index = 50)
				return -1
		}
	}
	
	finalPyStr := (pyStr="") ? Selection() : pyStr ; if a string has been passed into this function then use that as the python code, otherwise use the currently selected text using my custom Selection() function
	if(StrLen(finalPyStr) > 0){ ; Only do the following if there is some python code to run
		DllCall("LoadLibrary", "Str", PythonDll)
		DllCall(PythonDll "\Py_Initialize", "Cdecl")
		DllCall(PythonDll "\PyRun_SimpleString", "AStr", finalPyStr)
		DllCall(PythonDll "\Py_Finalize", "Cdecl")
	}
	return 1
}
 
;the below Selection() function is a dependency for RunPython() so that it can retrieve the contents of highlighted text
Selection(WaitTime:=0.5, ByRef TempClipSaved:="NotPassed"){
	;returns the selected text. Optionally pass in the 'wait time' which prevents the action timing out for the defined amount of time (seconds). 
	;Optionally pass in a byref variable to TempClipSaved to hold the old clipboardAll data - to rewrite later. This will also stop the function from rewriting the original clipboard
	;Alternatively simply change the TempClipSaved value to any arbitrary string to avoid rewriting the original clipboard
	bolRewriteClip := (TempClipSaved="NotPassed") ? 1 : 0
	TempClipSaved := ClipboardAll
	Clipboard=
	Send, ^c
	ClipWait,%WaitTime%
	TempSelection := (ErrorLevel)? "" : Clipboard
	if(bolRewriteClip)
		Clipboard := TempClipSaved
	return, TempSelection
}
The reason why the popup is in Japanese text with python 2.7 is because I used the Unicode message box of the python ctypes library. In Python 2.7 you could use ctypes.windll.user32.MessageBoxA(0, "Brought to you by the knights who say ni", "Python Message Box", 1) (Note the MessageBoxA instead of the MessageBoxW)

I know soooo little about Python or any other languages, and I've chosen Python and am desperately trying to learn it. I intend to use this little RunPython() function to help me get into it, since it will allow me to run short snippets of python code with a hotkey.

Return to “Ask For Help”

Who is online

Users browsing this forum: Bing [Bot], flyingDman, Google [Bot], guest3456, Sweetins and 186 guests