Using functions from a .dll file

Get help with using AutoHotkey and its commands and hotkeys
AutomatonMan
Posts: 2
Joined: 13 Sep 2018, 08:05

Using functions from a .dll file

13 Sep 2018, 08:49

Hey Guys!

I'm new to the forums, but have been using AHK for a little while. I use it primarily for productivity at work. I have shortcuts to write things out, file shortcuts etc. I work in industrial refrigeration and have recently discovered a refrigerant properties reference called coolprop. Coolprop basically provides a tool to calculate the properties of various pure and mixed fluids at nearly any condition. I am interested in building something to utilize the functions of coolprop within autohotkey. There is a lot of documentation from coolprop about using it in other programs, but not in AHK. Below is some information for how it is included in excel using VBA

Code: Select all

'Information on calling DLL from Excel:
'http://msdn.microsoft.com/en-us/library/office/bb687915.aspx
'
'Information on compiling DLL:
'http://msdn.microsoft.com/en-us/library/office/bb687850.aspx

'Information on 32-bit/64-bit compatibility (64-bit only has one harmonized calling convention)
'http://msdn.microsoft.com/en-us/library/office/ff700513%28v=office.11%29.aspx

' If you use older versions of Excel, you might need to remove the PtrSafe from the function definition

Option Explicit
#If Mac Then
    ' see http://stackoverflow.com/a/39821415/1360263 for info on interrogating the version of Excel
    #If MAC_OFFICE_VERSION >= 15 And VBA7 Then ' 64-bit Excel 2016 for Mac
        ' Even though the functions are exported with a leading underscore, Excel 2011 for Mac doesn't want the leading underscore as part of name
        Private Declare PtrSafe Function PropsSI_private Lib "libCoolProp.dylib" Alias "PropsSI" (ByVal output As String, ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal Ref As String) As Double
        Private Declare PtrSafe Function PhaseSI_private Lib "libCoolProp.dylib" Alias "PhaseSI" (ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal Ref As String, ByVal output As String, ByVal n As Integer) As Long
        Private Declare PtrSafe Function Props1SI_private Lib "libCoolProp.dylib" Alias "Props1SI" (ByVal output As String, ByVal Ref As String) As Double
        Private Declare PtrSafe Function get_global_param_string_private Lib "libCoolProp.dylib" Alias "get_global_param_string" (ByVal param As String, ByVal output As String, ByVal n As Integer) As Long
        Private Declare PtrSafe Function get_fluid_param_string_private Lib "libCoolProp.dylib" Alias "get_fluid_param_string" (ByVal fluid As String, ByVal param As String, ByVal output As String, ByVal n As Integer) As Long
        Private Declare PtrSafe Function HAPropsSI_private Lib "libCoolProp.dylib" Alias "HAPropsSI" (ByVal output As String, ByVal Input1Name As String, ByVal Value1 As Double, ByVal Input2Name As String, ByVal Value2 As Double, ByVal Input3name As String, ByVal Value3 As Double) As Double
        Public Declare PtrSafe Function set_config_string Lib "libCoolProp.dylib" (ByVal key As String, ByVal value As String) As Long
        'DEPRECATED
        Private Declare PtrSafe Function Props_private Lib "libCoolProp.dylib" Alias "PropsS" (ByVal output As String, ByVal Name1 As Long, ByVal Value1 As Double, ByVal Name2 As Long, ByVal Value2 As Double, ByVal Ref As String) As Double
    #Else ' 32-bit Excel for Mac
        ' Even though the functions are exported with a leading underscore, Excel 2011 for Mac doesn't want the leading underscore as part of name
        Private Declare PtrSafe Function PropsSI_private Lib "libCoolProp_32bit.dylib" Alias "PropsSI" (ByVal output As String, ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal Ref As String) As Double
        Private Declare PtrSafe Function PhaseSI_private Lib "libCoolProp_32bit.dylib" Alias "PhaseSI" (ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal Ref As String, ByVal output As String, ByVal n As Integer) As Long
        Private Declare PtrSafe Function Props1SI_private Lib "libCoolProp_32bit.dylib" Alias "Props1SI" (ByVal output As String, ByVal Ref As String) As Double
        Private Declare PtrSafe Function get_global_param_string_private Lib "libCoolProp_32bit.dylib" Alias "get_global_param_string" (ByVal param As String, ByVal output As String, ByVal n As Integer) As Long
        Private Declare PtrSafe Function get_fluid_param_string_private Lib "libCoolProp_32bit.dylib" Alias "get_fluid_param_string" (ByVal fluid As String, ByVal param As String, ByVal output As String, ByVal n As Integer) As Long
        Private Declare PtrSafe Function HAPropsSI_private Lib "libCoolProp_32bit.dylib" Alias "HAPropsSI" (ByVal output As String, ByVal Input1Name As String, ByVal Value1 As Double, ByVal Input2Name As String, ByVal Value2 As Double, ByVal Input3name As String, ByVal Value3 As Double) As Double
        Public Declare PtrSafe Function set_config_string Lib "libCoolProp_32bit.dylib" (ByVal key As String, ByVal value As String) As Long
        'DEPRECATED
        Private Declare PtrSafe Function Props_private Lib "libCoolProp_32bit.dylib" Alias "PropsS" (ByVal output As String, ByVal Name1 As Long, ByVal Value1 As Double, ByVal Name2 As Long, ByVal Value2 As Double, ByVal Ref As String) As Double
    #End If

#ElseIf Win64 Then
    Private Declare PtrSafe Function get_global_param_string_private Lib "CoolProp_x64.dll" Alias "get_global_param_string" (ByVal param As String, ByVal output As String, ByVal n As Integer) As Long
    Private Declare PtrSafe Function get_fluid_param_string_private Lib "CoolProp_x64.dll" Alias "get_fluid_param_string" (ByVal fluid As String, ByVal param As String, ByVal output As String, ByVal n As Integer) As Long
    Private Declare PtrSafe Function PropsSI_private Lib "CoolProp_x64.dll" Alias "PropsSI" (ByVal output As String, ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal Ref As String) As Double
    Private Declare PtrSafe Function PhaseSI_private Lib "CoolProp_x64.dll" Alias "PhaseSI" (ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal Ref As String, ByVal output As String, ByVal n As Integer) As Long
    Private Declare PtrSafe Function Props1SI_private Lib "CoolProp_x64.dll" Alias "Props1SI" (ByVal output As String, ByVal Ref As String) As Double
    Private Declare PtrSafe Function HAPropsSI_private Lib "CoolProp_x64.dll" Alias "HAPropsSI" (ByVal output As String, ByVal Input1Name As String, ByVal Value1 As Double, ByVal Input2Name As String, ByVal Value2 As Double, ByVal Input3name As String, ByVal Value3 As Double) As Double
    Public Declare PtrSafe Function set_config_string Lib "CoolProp_x64.dll" (ByVal key As String, ByVal value As String) As Long
    'DEPRECATED
    Private Declare PtrSafe Function Props_private Lib "CoolProp_x64.dll" Alias "PropsS" (ByVal output As String, ByVal Name1 As Long, ByVal Value1 As Double, ByVal Name2 As Long, ByVal Value2 As Double, ByVal Ref As String) As Double
#Else
    Private Declare PtrSafe Function get_global_param_string_private Lib "CoolProp_stdcall.dll" Alias "_get_global_param_string@12" (ByVal param As String, ByVal output As String, ByVal n As Integer) As Long
    Private Declare PtrSafe Function get_fluid_param_string_private Lib "CoolProp_stdcall.dll" Alias "_get_fluid_param_string@16" (ByVal param As String, ByVal param As String, ByVal output As String, ByVal n As Integer) As Long
    Private Declare PtrSafe Function PropsSI_private Lib "CoolProp_stdcall.dll" Alias "_PropsSI@32" (ByVal output As String, ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal Ref As String) As Double
    Private Declare PtrSafe Function PhaseSI_private Lib "CoolProp_stdcall.dll" Alias "_PhaseSI@36" (ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal Ref As String, ByVal output As String, ByVal n As Integer) As Long
    Private Declare PtrSafe Function Props1SI_private Lib "CoolProp_stdcall.dll" Alias "_Props1SI@8" (ByVal output As String, ByVal Ref As String) As Double
    Private Declare PtrSafe Function HAPropsSI_private Lib "CoolProp_stdcall.dll" Alias "_HAPropsSI@40" (ByVal output As String, ByVal Input1Name As String, ByVal Value1 As Double, ByVal Input2Name As String, ByVal Value2 As Double, ByVal Input3name As String, ByVal Value3 As Double) As Double
    Public Declare PtrSafe Function set_config_string Lib "CoolProp_stdcall.dll" Alias "_set_config_string@8" (ByVal key As String, ByVal value As String) As Long
    'DEPRECATED
    Private Declare PtrSafe Function Props_private Lib "CoolProp_stdcall.dll" Alias "_PropsS@32" (ByVal output As String, ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal Ref As String) As Double
#End If

Public Function get_env_variable(ByVal key As String) As String
    Dim script As String
    Dim output As String
    #If Mac Then
        script = "set pp to system attribute """ & key & """" & vbNewLine & "return pp"
        output = MacScript(script)
    #Else
        output = Environ(key)
    #End If
    get_env_variable = output
End Function
Private Function get_error_message() As String
    Dim errstring As String
    'Make a null-terminated string that is plenty big
    errstring = String(2000, vbNullChar)
    'Get the error string
    Call get_global_param_string_private("errstring", errstring, 2000)
    get_error_message = errstring
End Function

Public Function get_global_param_string(ByVal output As String) As String
    Dim strParam As String
    'Make a null-terminated string that is plenty big
    strParam = String(2000, vbNullChar)
    'Get the version string
    Call get_global_param_string_private(output, strParam, 2000)
    get_global_param_string = strParam
End Function

Public Function PropsSI(ByVal output As String, ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal fluid As String)
    On Error GoTo ErrorHandler
    Dim PropsSI_temp As Double

    PropsSI_temp = PropsSI_private(output, Name1, Value1, Name2, Value2, fluid)
    
    If Abs(PropsSI_temp) > 1E+30 Then
        'Return error message
        PropsSI = get_error_message()
    Else
        PropsSI = PropsSI_temp
    End If
    Exit Function
    
ErrorHandler:
    If Err = 13 Then
     Exit Function
    End If
    
    MsgBox "The most recent error number is " & Err & ". Its message text is: " & Error(Err)
    Exit Function
End Function

Public Function PhaseSI(ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal fluid As String)
    Dim strPhase As String
    'Make a null-terminated string that is plenty big
    strPhase = String(2000, vbNullChar)
    'Call PhaseSI_private - any errors will return an empty phase string
    Call PhaseSI_private(Name1, Value1, Name2, Value2, fluid, strPhase, 2000)
    If Len(strPhase) = 0 Then
        PhaseSI = get_error_message()
    Else
        PhaseSI = strPhase
    End If
    Exit Function
End Function

Public Function Props1SI(ByVal fluid As String, ByVal output As String)
    On Error GoTo ErrorHandler
    Dim Props1SI_temp As Double
    
    Props1SI_temp = Props1SI_private(output, fluid)
    
    If Abs(Props1SI_temp) > 1E+30 Then
        'Display the error
        Props1SI = get_error_message()
    Else
        Props1SI = Props1SI_temp
    End If
    Exit Function
    
ErrorHandler:
    If Err = 13 Then
     Exit Function
    End If
    MsgBox "The most recent error number is " & Err & ". Its message text is: " & Error(Err)
    Exit Function
End Function

Public Function Props(ByVal output As String, ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal fluid As String)
    On Error GoTo ErrorHandler
    Dim Props_temp As Double
    Props_temp = Props_private(output, Name1, Value1, Name2, Value2, fluid)
    If Abs(Props_temp) > 1E+30 Then
        Props = get_error_message()
    Else
        Props = Props_temp
    End If
    Exit Function
ErrorHandler:
    If Err = 13 Then
     Exit Function
    End If
    MsgBox "The most recent error number is " & Err & ". Its message text is: " & Error(Err)
    Exit Function
End Function

Public Function HAPropsSI(ByVal output As String, ByVal Input1Name As String, ByVal Value1 As Double, ByVal Input2Name As String, ByVal Value2 As Double, ByVal Input3name As String, ByVal Value3 As Double) As Double
    On Error GoTo ErrorHandler
    Dim HAPropsSI_temp As Double
    HAPropsSI_temp = HAPropsSI_private(output, Input1Name, Value1, Input2Name, Value2, Input3name, Value3)
    If Abs(HAPropsSI_temp) > 1E+30 Then
        HAPropsSI = get_error_message()
    Else
        HAPropsSI = HAPropsSI_temp
    End If
    Exit Function
ErrorHandler:
    If Err = 13 Then
     Exit Function
    End If
    MsgBox "The most recent error number is " & Err & ". Its message text is: " & Error(Err)
    Exit Function
End Function

Public Function MixtureString(names As Range, fractions As Range) As String
    ' See http://www.functionx.com/vbaexcel/objects/Lesson6.htm
    Dim my_names, my_fractions As Collection
    Dim Cell, i As Variant
    Dim chunk As String
    MixtureString = ""
    Set my_names = New Collection
    Set my_fractions = New Collection
    
    ' Collect all the names
    For Each Cell In names
        my_names.Add Cell.value
    Next
    ' Collect all the fractions
    For Each Cell In fractions
        my_fractions.Add Cell.value
    Next
    ' Zip them back together
    For i = 1 To my_fractions.Count
        chunk = my_names.Item(i) & "[" & LTrim(Str(my_fractions.Item(i))) & "]"
        If i = 1 Then
            MixtureString = MixtureString & chunk
        Else
            MixtureString = MixtureString & "&" & chunk
        End If
    Next

End Function
What I want to be able to do is call the PropsSI() function in autohotkey.

I'm probably a little out of my depth here, but any suggestions on calling this in AHK would be greatly appreciated!
AutomatonMan
Posts: 2
Joined: 13 Sep 2018, 08:05

Re: Using functions from a .dll file

19 Sep 2018, 14:20

So, I've tried a little bit. The below is what I came up with to test.

^+t::

nh3Press = 202000
nh3Temp := DllCall("C:\Users\josiah.royer\AppData\Roaming\CoolProp\CoolProp_x64.dll\propsSI", "str", "T", "str", "P", "double", %nh3press%, "str", "Q", "double", 0, "str", "ammonia")

MsgBox, , Ammonia Temperature, The temperature of the ammonia is %nh3Temp% at %nh3Press%

return

However, my result is always a blank. not sure what I'm missing here...
User avatar
Flipeador
Posts: 1018
Joined: 15 Nov 2014, 21:31
GitHub: Flipeador
Location: Argentina
Contact:

Re: Using functions from a .dll file

19 Sep 2018, 15:36

Try this (not tested):

Code: Select all

DllFile := "C:\Users\josiah.royer\AppData\Roaming\CoolProp\CoolProp_x64.dll"
hModule := DllCall("LoadLibrary", "UPtr", &DllFile, "UPtr")

nh3Press := 202000
nh3Temp := DllCall(DllFile . "\PropsSI", "AStr", "T", "AStr", "P", "Double", nh3Press, "AStr", "Q", "Double", 0, "AStr", "ammonia", "Double")
MsgBox % nh3Temp
Windws 1♂ Pro 64-Bits I make scripts for AHKv2 (my v2 compiler) & WIN_7+ Spanish Argentina SublimeText 3 & AHKv2 My GDI+ Library
User avatar
Gio
Posts: 472
Joined: 30 Sep 2013, 10:54
Location: Brazil

Re: Using functions from a .dll file

19 Sep 2018, 16:43

Flipeadors code works.

Here are my 2 cents:

Setting DllCall() is basically a matter of
  • 1. Inputing the correct file and function names (i.e.: c:/file.dll/function)
  • 2. Inputing the correct types in each parameter (str, Int, Ptr, etc)
  • 3. Setting the correct convention call (if needed).
In following these steps, we create templates of autohotkey code that can be easily used to make new valid calls at will (by adjusting only the parameter values).

:arrow: So this is how you can create template code in AutoHotkey to use the CoolProp library at will:

From the examples in their site, we know that this unknown-language-code call:

Code: Select all

PropsSI('D', 'T', 298.15, 'P', 100e5, 'CO2')
Should yield 817.6273812375758

And also, that this other example:

Code: Select all

PropsSI('H', 'T', 298.15, 'Q', 1, 'R134a')
Should yield 412333.95323186804

Therefore, we can use these samples to set our DllCall()s, attempting to write a call to PropsSI function that returns the exact same values.

First, let's check for correct files/function names. The library contains multiple files, so only by checking the documentation of the library, we can infer the correct files and the parameter type descriptions we need. From the documentation info you have provided, we see this info for windows 64bit:

Code: Select all

Private Declare PtrSafe Function PropsSI_private Lib "CoolProp_x64.dll" Alias "PropsSI" ...
And from that we can infer the file/function we need. Thus, we need the file the file CoolProp_x64.dll, and for ease of use, let's place it in the same folder as the script.

Second, we need to check for parameter types. Thus, from the info you have provided, we have this for windows 64bit:

Code: Select all

... "PropsSI" (ByVal output As String, ByVal Name1 As String, ByVal Value1 As Double, ByVal Name2 As String, ByVal Value2 As Double, ByVal Ref As String) As Double
And from it, we can than set the parameter types accordingly.

Third, there are no mentions of specific convention calls, and so we have everything we need to make our call:

Code: Select all

DllFile := A_ScriptDir . "\CoolProp_x64.dll"
hModule := DllCall("LoadLibrary", "UPtr", &DllFile, "UPtr")

Value1 := DllCall(DllFile . "\PropsSI"
, "AStr", "D"
, "AStr", "T"
, "Double", 298.15
, "AStr", "P"
, "Double", 10000000
, "AStr", "CO2"
, "Double")

msgbox % Value1

Value2 := DllCall(DllFile . "\PropsSI"
, "AStr", "H"
, "AStr", "T"
, "Double", 298.15
, "AStr", "Q"
, "Double", 1
, "AStr", "R134a"
, "Double")

msgbox % Value2
* Code above has been tested on AutoHotkey 64bit Unicode only.

If the code above works, you can now use it as a template for calling the PropsSI function of the CoolProp_x64.dll file whenever you need. Change the values to make new calculations, but remenber to leave the parameter types and file/function names in the template intact.

The same process can be repeated to make templates for the other functions (search for sample code with expected value, search for parameter description, set DllCall(), test, etc) in the library.

:!: Note:
For the last parameter, you can get a list of fluids here.
For a list of possible values in the other string paramters, check the table of string input values here.
"What is suitable automation? Whatever saves your day for the greater matters."
Barcoder - Create QR Codes and other Barcodes using only Autohotkey !!

Return to “Ask For Help”

Who is online

Users browsing this forum: cedric3d, chngrcn, Google [Bot], Oobee, roysubs and 27 guests