I have a console app, myapp.exe. Within the app is a function, let's call it:
public static int AddIntegers(int a, int b)
Is it possible to make this function visible externally so that a VBscript could call it? Do I have to move the function into a DLL or can I leave it in the EXE and make it visible? If so, how?
Idealistically, you should be making a DLL and set Com Visible on the functions you need to expose.
using System;
using System.Runtime.InteropServices;
namespace MyDLL
{
[ComVisible(true)]
public class Operations
{
[ComVisible(true)]
public int AddIntegers(int a, int b)
{
return a + b;
}
}
}
After you've compiled your DLL you need to register it with regasm.exe so that you can call it from VBScript:
Dim myObj
Set myObj = CreateObject("MyDLL.Operations")
Dim sum
sum = myObj.AddIntegers(3, 5)
This reply is based on the CodeProject posting How to call a .NET DLL from a VBScript by Raymund Macaalay. I recommend you read it.
Also, you should check other stackoverflow posting such as How to call C# DLL function from VBScript.
Yes, you will need to make the managed code library (DLL) visible to the VBScript (most likely through the GAC). Then in your VBScript, you can do something like:
dim yourObject = CreateObject("YourContainingObject");
yourObject.AddIntegers yourFirstInt, yourSecondInt
Related
I created a C# Dll that use "Register for com interop" and I managed to register it using RegAsm:
RegAsm.exe -tlb -codebase MathLib.dll
After that I got the message:
"Assembly exported to 'C:\Test\MathLib.tlb', and the type library was registered successfully"
How do I call now the methods inside the Dll? For example it has a public function:
int Add(int a, int b) { return a + b; }
that adds 2 numbers and return the result. How do I call it from the command-line and see the result of the operation?
Thanks very much.
How does it work?
Create a new classlibrary or proceed with an
existing one. Then add the UnmanagedExports Nuget package.
This is pretty much all setup that is required.
Now you can write any kind of static method, decorate it with
[DllExport] and use it from native code. It works just like DllImport,
so you can customize the marshalling of parameters/result with
MarshalAsAttribute.
During compilation, my task will modify the IL to add the required
exports.
A good example would be the following lines:
class Test
{
[DllExport("Add", CallingConvention = CallingConvention.Cdecl)]
public static int Add(int a, int b)
{
return a + b;
}
}
As you know, keep registering your lib with RegAsm. To import your COM function back on another project, you shall Marshall it like a native method, declaring it in your code with the [DLLImport] attribute.
References:
Unmanaged Exports
UnmanagedExports Nuget package
I hope that helped in someway.
I've been requested to create a .Net dll for an old delphi program. I'm trying to do this with a COM Callable Wrapper, but I keep getting an error when it tries to load the dll (pretty general, something like "I couldn't load the dll"). Here is what the technical documentation says:
The DLL only needs to export one function under the name 'AUTHORIZE'.
function Authorize(InXml: PChar): PChar; stdcall;
(Delphi syntax. May be different in other languages.)
Here is my code for the CCW:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ComCallableWrapper
{
[Guid("C3FD922A-FB44-47B1-9C0C-8F7FAF57098B")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IAuthorizer
{
[DispId(1)]
string Authorize(string lnpInXml);
}
[ProgId("ComCallableWrapper.Authorizer")]
[ClassInterface(ClassInterfaceType.None)]
public class Authorizer : IAuthorizer
{
public Authorizer()
{
}
public string Authorize(string lnpInXml)
{
return "Approved!";
}
}
}
I also run this command "regasm /tlb:ComCallableWrapper.tlb ComCallableWrapper.dll /codebase" on the computer where the delphi program is running.
I've been doing some research on google about how delphi invokes functions on a dll, and I found at least 2 ways:
function Authorize(lnpInXml: pchar): pchar; stdcall; external 'DLLName.dll';
and
oleObject := CreateOleObject('ComCallableWrapper.Authorizer');
ShowMessage(oleObject.Authorize('Approved?'));
It looks like COM works a little bit different. Is there a way to change my CCW to work like the first way?
Regards.
You con't need COM. And indeed using COM is a mistake because the Delphi program is not looking for a COM DLL.
What you need to do is to export an unmanaged function from your managed C# DLL. That's a little tricky and is in fact not supported. These are your most attractive options:
Use Robert Giesecke's UnmanagedExports.
Write a mixed mode C++/CLI DLL that consumes your C# code. The mixed mode C++/CLI is capable of export native functions using __declspec(dllexport), .def files etc.
If you chose to use UnmanagedExports, the function would look like this:
[DllExport]
public static IntPtr Authorize(string InXml)
{
// your code goes here, for now return the input value
return Marshal.StringToHGlobalAnsi(InXml);
}
Implementing the function is a little tricky because you need to return a Delphi PAnsiChar, that is a C++ char*. You cannot use string for the return type and have to use IntPtr. But how do you allocate the string so that it remains valid for the caller to use it. The code above leaks the string in an HGLOBAL.
I can't advise you definitively how to resolve the lifetime of the string. The interface you are coding to is not at all well designed. Only you with more knowledge of the interface are in a position to resolve that issue.
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
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.
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")
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.
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.
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.
I am currently developing an application in C# which needs to work sort of like a "Command Prompt", therefore I was wondering whether the C++ function
int system ( const char * command );
in cstdlibexists in C#?
A reference to an dynamic-link library containing this function would be accepted aswell.
Look into System.Diagnostics.Process.Start: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.start.aspx
If you want to execute program from an application then you can use 'Process' class,it's insanely easy,
using System.Diagnostics;
class Program
{
static void Main()
{
Process.Start("MyApp.exe");
}
}
You might use a Console Application project template in Visual Studio,
I have to replace an existing dll call that is registered and called using RegFn and CallFn respectively.
I am trying to write the dll using C# in the hope that as long as the function signature match and the dll is in the right place it will work.
so
pnHndl= RegFn("CALCULATE", "I", "I", "AJons.DLL")
pnRetVal = CallFn(pnHndl, 0)
My code is as follows:
[Guid("EAB7C2CD-2471-4BDA-90E9-F70403BAA557")]
[ComVisible(true)]
public class AJons : _AJons
{
[ComVisible(true)]
public int CALCULATE(int value)
{
return value * 2;
}
}
Foxpro doesn't play ball I just get 'could not load library AJon.dll'
Does anyone have any experience here?
Cheers.
From what I can see, those really old RegFn and CallFn are for calling Win32 native Dlls - completely different from COM.
What you need to create a Win32 dll that will work with those functions is C++.
What you should do (if you HAVE to keep using FoxPro) is at least use the latest version of VFP.
written on my iPhone
Update 1
1) Just in case I wasn't clear, you cannot make this kind of DLL from .NET.
2) Have a look at this link here for a very simple example of how to write a Win32 dll.