4

I think I'm in over my head here, but wondering if anyone can point me in the right direction. I've created a C# class library (dll) in Visual Studio 2010 to interact with a MS SQL server. It works fine when I call it from another C# program. However, when I try and call it from an AHK script I get the "Error level = -4" indicating the function can't be found.

Here's my C# code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;

namespace AHK_Interface
{
    public class AHK_Interface
    {
        public string TrackUsage()
        {
            try
            {
                SqlConnection ahk_connection = new SqlConnection("Data Source=SQLServer;Initial Catalog=AHK;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False");
                SqlCommand cmd;
                ahk_connection.Open();
                cmd = new SqlCommand("INSERT INTO AHK_USAGE(username,script_version,notes) VALUES ('TEST user','1.01','TEST NOTES')",ahk_connection);
                cmd.Connection = ahk_connection;
                cmd.ExecuteNonQuery();
                string success_ind = "success!";
                ahk_connection.Close();
                return success_ind;
            }
            catch (Exception e)
            {
                string success_ind = e.Message;
                return success_ind;
            }
        }
    }
}

I went into regasm.exe and registered the DLL successfully.

Here's my Autohotkey code where I'm trying to call it. All this method does is perform and insert statement and return a success/no success string so I didn't think I'd need to pass any parameters to it.

SetWorkingDir %A_ScriptDir%
DllCall("LoadLibrary", "str", "AHK_Interface.dll")
msgbox %ErrorLevel% ;good at this point
success_ind := DllCall("AHK_Interface\TrackUsage") ;trying to call my method "TrackUsage" above
MsgBox, %success_ind% %ErrorLevel% ;gives error level of -4 here

ExitApp
colinwurtz
  • 703
  • 1
  • 7
  • 23
  • Very interesting. I don't have any answer, but I'm watching this thread! You don't always have to register a DLL to use - if the DLL is in the same directory as the app, it might just use it without any problem. – bgmCoder Dec 04 '13 at 16:45

5 Answers5

5

A little bit late but I had the same problem and by using the suggested comments, it works.

This is how I did it:

1) Make the C# class static.

2) Use the 'UnmanagedExports' as already pointed out.

3) Make sure to use the DllExport name in the dll call, like this:

[DllExport("add", CallingConvention = CallingConvention.Cdecl)]
public static string TrackUsage()
{...}

4) Then call the dll by:

dataVariable := DllCall("AHK_Interface\add", "Cdecl Str")
4

Use the NuGet package UnmanagedExports to mark the method as callable from a non-.Net external program. Use DllCall inside AHK to call the function.

Joel Lucsy
  • 8,520
  • 1
  • 29
  • 35
  • I didn't even know these existed. I had to change my class to static and wrap the DLL export line above my method. The build succeeded fine, but still having no luck getting anything from Autohotkey. I'll keep trying since it's probably just something I'm doing wrong. Thanks for the help! – colinwurtz Dec 04 '13 at 19:38
  • I've gotten this to work, but it's pretty finicky about where the dll resides. I believe the dll has to reside in a directory on the path, or in the current directory from where the ahk is run from, although I've had problems with current directory not working if you're double-clicking from explorer. Works better from command line. – Joel Lucsy Dec 04 '13 at 20:04
  • I too didn't know this existed. Thanks! – hyru Dec 04 '13 at 22:14
2

DllCall has no concept of .NET types or methods, and only works with exported native windows functions.

You have three options:

1) Build a native assembly that hosts the .NET CLR to call your managed code.

2) Use CLR for AutoHotkey instead of building your own CLR hosting framework.

3) Alternatively, call AHK from .NET by referencing AutoHotkey.dll in your C# application and call ahktextdll.

Community
  • 1
  • 1
hyru
  • 189
  • 6
1

Ah, one thing I notice is this:

public class AHK_Interface

Your class is public but not static - that means you have to create a new instance of the class in order to use it. Try adding static to your class and see if it helps.

Also, in your dll, add a messagebox popup for any error that might happen - maybe put this in your try/catch statement.

Also, you might like to take a look at this thread from Autohotkey.net - it is called .NET Framework Interop.

bgmCoder
  • 6,205
  • 8
  • 58
  • 105
0

Make sure that if you are on 64-bit architecture, you are targeting x64 in your build configuration. If it is set to ANY it will return -4.

TrialAndError
  • 1,784
  • 3
  • 20
  • 41