I am trying access methods of a C# DLL (created one) from PowerBuilder but getting Error: Error calling external function.
C# Code
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
namespace AESKeyGen
{
public static class AESKeyGen_
{
static string secretKey;
private static byte[] generateAppKey()
{
Aes KEYGEN = Aes.Create();
byte[] secretKey = KEYGEN.Key;
return secretKey;
}
[DllExport("AESKey_generate", CallingConvention = CallingConvention.StdCall)]
public static string AESKey_generate()
{
secretKey = Convert.ToBase64String(generateAppKey());
return secretKey;
}
}
}
PowerBuilder Code
FUNCTION string AESKey_generate() LIBRARY "AESKeyGen.dll
ls_AESKey = AESKey_generate()
I could able to test this DLL using another C# app successfully by adding reference.
tried to check methods exported by AESKeyGen DLL using depends.exe but could not any methods listed there.
I did try few things mentioned on internet but no luck.
please suggested.
Related
I'm creating a dll in C# which runs a simulation when a single function runSimulation() is called. This dll should be called from VBA, as certain parameter values are given as input in Excel. This is the code I use.
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using RGiesecke.DllExport;
namespace Simulation
{
public static class Simulation
{
[ComVisible(true)]
[DllExport("runSimulation", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.SysInt)]
public static int runSimulation()
{
// Do simulation
return 0;
}
}
}
The above code is compiled as a Class Library with x64 as Platform Target and returns Simulation.dll.
VBA:
Public Declare Function runSimulation Lib "Simulation.dll" () As Long
Sub Run_DLL()
ChDir (ActiveWorkbook.Path)
Dim returnValue As Long
returnValue = runSimulation()
End Sub
Running the Visual Basic code returns
run-time error 453: 'Can't find DLL entry point runSimulation in
Simulation.dll'
when it tries to call runSimulation().
As a reference: I've tried running with
[DllExport("runSimulation", CallingConvention = CallingConvention.StdCall)]
instead, but this also doesn't work. I additionally tried using the advice given in https://www.linkedin.com/grp/post/40949-258782989 but it gives me the same error.
I managed to call the 'runSimulation' function in VBA code, by exposing the Simulation class through an interface in C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace NSSimulation
{
public interface ISimulation
{
int runSimulation();
}
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Simulation : ISimulation
{
[ComVisible(true)]
public int runSimulation()
{
return 0;
}
}
}
Then re-compile your project and export your rebuilt library with 'tlbexp.exe' from the Visual Studio command prompt:
tlbexp.exe SimulationLib.dll /out:"SimulationLib.tlb" /win64
Then open the Visual Basic editor in Excel and add a reference to 'SimulationLib.tlb' through "Tools->References->Browse". To verify
Public x As New SimulationLib.Simulation
Sub test()
MsgBox x.runSimulation
End Sub
I have written a class library. To execute methods that I wrote in my class library, I created a console application. In my console application, I added the class library that I wrote as a reference. I then added the appropriate using statement to my console application. My methods from this library are inaccessible currently. Why?
Here's my class library with a basic method. It was created in .NET framework 3.5.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.Geometry;
namespace RelateTablesValidation
{
[Guid("e1058544-0d84-49be-a406-b4e65707f95b")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("RelateTablesValidation.Validate")]
[ComVisible(true)]
public class Validate : ESRI.ArcGIS.Geodatabase.IClassExtension, ESRI.ArcGIS.Geodatabase.IObjectClassExtension, ESRI.ArcGIS.Geodatabase.IRelatedObjectClassEvents2
{
public void ChangeClassExtension(IObjectClass objectClass, String extensionUID, IPropertySet extensionProperties)
{
ISchemaLock schemaLock = (ISchemaLock)objectClass;
try
{
// Attempt to get an exclusive schema lock.
schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);
// Cast the object class to the IClassSchemaEdit2 interface.
IClassSchemaEdit2 classSchemaEdit = (IClassSchemaEdit2)objectClass;
if (!String.IsNullOrEmpty(extensionUID))
{
// Create a unique identifier (UID) object and change the extension.
UID extUID = new UIDClass();
extUID.Value = extensionUID;
classSchemaEdit.AlterClassExtensionCLSID(extUID, extensionProperties);
}
else
{
// Clear the class extension.
classSchemaEdit.AlterClassExtensionCLSID(null, null);
}
}
catch (COMException comExc)
{
throw new Exception("Could not change class extension.", comExc);
}
finally
{
schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
}
}
}
Here's my console app. RelateTablesValidation is the class library. Also created in .NET Framework 3.5
using System;
using System.Collections.Generic;
using System.Text;
using RelateTablesValidation;
using Esri.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DatasourcesGDB;
namespace ApplyClassExtension
{
class Program
{
[STAThread()]
static void Main(string[] args)
{
//system sees objects from this namespace OK
IWorkspaceFactory workspaceFactory = new FileGDBWorkspaceFactory();
//now when i try to call my method, it doesn't even show up in Intellisense
ChangeClassExtension(method params would go here);
}
}
}
You can't do what you're trying to do.
All methods in C# are inside of objects. You must either make the method static and call it like this:
Validate.ChangeClassExtension(...);
Or don't make it static and instantiate an instance of Validate:
var val = new Validate();
val.ChangeClassExtension(...);
I am trying to run a c# method in the IronPython (2.7.3) console:
The c# (compiled to a dll) is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PythonTest
{
public class PythonTest
{
public PythonTest(){}
public int GetOne()
{
return 1;
}
public double Sum(double d1, double d2)
{
return d1+d2;
}
public string HiPlanet()
{
return "Hi Planeta";
}
}
}
the python is
import sys
sys.path.append("Y:\\")
import clr
clr.AddReferenceToFile('./PythonTest')
import PythonTest
a = PythonTest.PythonTest.GetOne()
I get a TypeError in ironpython saying that the function takes one arguement (which it doesn't according to my c#!). I am confused and woudl appeciate help here, I'm just trying to call some c# functions provide the arguements and get the results, thanks in advance!
Since it's an instance method, you need to instantiate the object before calling GetOne method:
obj = PythonTest.PythonTest()
a = obj.GetOne()
or, in one-liner:
a = PythonTest.PythonTest().GetOne()
I have a trouble invoking C function from my C# code. I wanted to add some functionality to VLC player(we use it in our software through vlcdotnet) and cross-compiled it on my ubuntu 12.10 for windows using mingw. I wrote a function, let's call it Foo:
__declspec(dllexport) void Foo(vlc_object_t* bar);
Now I want to call it from C#:
[LibVlcFunction("Foo")]
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void Foo(IntPtr pointer);
........
public LibVlcFunction<Foo> Foo { get; private set; }
......
Foo = new LibVlcFunction<Foo>(myLibVlcCoreDllHandle, VlcVersion);
And it fails. Inside constructor of LibVlcFunction we have combination of GetProcAddress and GetDelegateForFunctionPointer. GetProcAddress fails with "The address of function 'Foo' doesn't exists...." but dumpbin and dep. walker are saying that function exists and her name is not mangled. I tried to write a C++ app that loads a libvlc.dll and gets pointer to my func and it worked. But in C# it fails. What should I do? Any suggestions?
Try not using stdcall and, instead, use cdecl, like this:
extern "C" __declspec(dllexport) void Foo(vlc_object_t* bar);
Your platform invoke call, would like this:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
public class libvlc
{
[DllImport("the-vlc.dll", EntryPoint = "Foo")]
extern public static void Foo( IntPtr bar );
}
You will treat vlc_object_t* as opaque handles. You just pass them around. This assumes that vlc_object_t's are allocated and freed in your VLC shared library (i.e. in the DLL).
I thought I knew how to do this, but obviously not so I'd appreciate some help!
I can't get my dll to register so I can instantiate it in a VBS, or elsewhere.
I wrote the following sample class, checked "Make assembly COM Visible", checked "Register for COM Interop", then built it.
When I try to instantiate it from VBS I get the "Activex component can't create object" error.
This is the class code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Smurf
{
public class Pants
{
public string Explode(bool Loud)
{
string result;
if (Loud)
result = "BANG";
else
result = "pop";
return result;
}
}
}
...and this is the VBS:
Dim a
Set a = CreateObject("Smurf.Pants")
msgbox("ok")
What else do I need to do?
Thanks :)
[edit]
Forgot to mention, after the first failure I tried REGSVR32 and REGASM - no help!
[/edit]
Note that when I try REGSVR32, I get this message:
The Module "C:...\Smurf.dll" was loaded but the entry-point DllRegisterServer was not found.
Make sure that "C:...\Smurf.dll" is a valid DLL or OCX file and then try again.
How helpful is that??
This is the latest version of the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace Smurf
{
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
public interface IPants
{
[DispId(1)]
string Explode(bool Loud);
}
[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IPantsEvents
{
string Explode(bool Loud);
}
[ComVisible(true)]
[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938"),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(IPantsEvents))]
public class Pants : IPants
{
public Pants() { }
[ComVisible(true)]
[ComRegisterFunction()]
public static void DllRegisterServer(string key) { }
[ComVisible(true)]
[ComUnregisterFunction()]
public static void DllUnregisterServer(string key) { }
[ComVisible(true)]
public string Explode(bool Loud)
{
string result;
if (Loud)
result = "BANG";
else
result = "pop";
return result;
}
}
}
There could be a few different things at play here. First, you'll want to use the regasm tool with the /codebase /tlb switch from an elevated command prompt (assuming Windows Vista, 7 or Windows Server 2008). Something like:
regasm "Path to Smurf.dll" /codebase /tlb
Once you have registered the dll using regasm you should be able to invoke it using VBS, VBA or VB6.
I was able to use early binding and late binding from VBA to call the Explode method. However, when I tried from VBScript I received the "ActiveX can't create object error as you did."
I'm running on Windows 7 64 bit, and I recalled that this can cause problems when compiling to 32 bit dlls and running them on 64 bit operating systems. On a whim, I fired up a command prompt and entered:
C:\Windows\SysWow64\CScript.exe "Path to VBScript"
The result was that the script ran correctly and displayed "Pop" on screen.
Here's the somewhat simplified C# code I used as well as the contents of the VBScript file.
namespace Smurf
{
[Guid("EAA4976A-45C3-4BC5-BC0B-E474F4C3C83F")]
public interface IPants
{
string Explode(bool Loud);
}
[Guid("7BD20046-DF8C-44A6-8F6B-687FAA26FA71"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IPantsEvents
{
string Explode(bool Loud);
}
[ComVisible(true)]
[Guid("0D53A3E8-E51A-49C7-944E-E72A2064F938")]
[ClassInterface(ClassInterfaceType.None)]
[ComSourceInterfaces(typeof(IPantsEvents))]
public class Pants : IPants
{
[ComVisible(true)]
public string Explode(bool Loud)
{
string result;
if (Loud)
result = "BANG";
else
result = "pop";
return result;
}
}
}
VBScript:
Dim x
Set x = CreateObject("Smurf.Pants")
MsgBox (x.Explode(False))
Set x = Nothing