I am trying to export code from a function in C# to Delphi. I used DllExport with stdcall convention and made some tests :it works. I tested for integers and strings as params. The problem occurs when I try to use a class from Aforge library in C#. Delphi returns an error: "External Exception E0434F4D".
public class ProcessClass
{
[DllExport(CallingConvention=CallingConvention.StdCall)]
public static void ProcessImage()
{
try
{
Erosion erosion = new Erosion();
}
catch (Exception Ex)
{
}
}
}
Delphi code:
procedure ProcessImage; stdcall; external 'C:\Users\Reznicencu Bogdan\source\repos\OCR\OCR\bin\x86\Release\OCR.dll';
procedure TForm1.FormCreate(Sender: TObject);
begin
ProcessImage;
end;
The error apears at Erosion.Actually every function I use from Aforge library generates an error. I used Try/catch because I know Delphi can't catch exceptions from unmanaged code but it still doesn't work.
How can I solve this error?
The event log says: First chance exception at $767EDDC2. Exception class EExternalException with message 'External exception E0434F4D'. Process Project1.exe (9528)
The problem appears to be related to the location of the AForge DLLs. If you place those, and your class library DLL, in the same directory as your Delphi executable then the error disappears.
Perhaps there is some other way to tell AForge where to locate its DLLs. I will leave that as an exercise for the reader to investigate.
Related
I'm trying to call a .NET DLL from Delphi 6.
The dynamic loading of the DLL using LoadLibrary() is working fine, and a handle is returned.
Handle := LoadLibrary(PChar(DLLName));
But, the GetProcAddress() function is returning nil, even though Handle is valid, and the function 'DLL_Version' exists.
GetProcAddress(Handle, 'DLL_Version');
The DLL code is posted below
[Guid("14fd1190-df04-488c-ab0f-b120ea3e3f3a")]
[ComVisible(true)]
public class UnManClass
{
[DllExport]
public static int DLL_Version()
{
return 251;
}
}
I've used UnmanagedExports nuget package to support the [DllExport] in C#.
Here is the DumpBin output:
Is there any way to solve this issue, or any alternative methods which work?
Use Delphi to call a .NET DLL, you can trying like this:
var
OBJ: Variant;
begin
try
OBJ := CreateOleObject('DLLName.UnManClass');
ShowMessage(IntToStr(OBJ.DLL_Version));
finally
OBJ := Unassigned;
end;
end
I have a problem with invoking a few functions from DLL (SDK of some camera). In source of .dll, there is function:
NET_SDK_API LONG CALL_METHOD NET_SDK_Login(char *sDVRIP,WORD wDVRPort,char *sUserName,char *sPassword,LPNET_SDK_DEVICEINFO lpDeviceInfo);
and I am trying to call it from .Net console app with following code:
[STAThread]
static void Main(string[] args)
{
long userid = 0;
_net_sdk_deviceinfo dinfo = new _net_sdk_deviceinfo();
short port = 6036;
try
{
if (DVR.NET_SDK_Init())
{
Console.WriteLine("ok");
userid = DVR.NET_SDK_Login("192.168.1.132", port, "admin", "123456", out dinfo);
userid.ToString();
}
else
{
Console.WriteLine("err");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.ReadKey();
}
i get following error:
A call to PInvoke function 'DVRtest!DVRtest.DVR::NET_SDK_Login' has
unbalanced the stack. This is likely because the managed PInvoke
signature does not match the unmanaged target signature. Check that
the calling convention and parameters of the PInvoke signature match
the target unmanaged signature.
Init passes fine but i cant get anything else. I tried dozen of solutions and I'm getting nowhere.
Here is source of dll and source of my .Net app. Thanks!
[edit]
As #david pointed out, CallingConvention was wrong and now, i get following error:
The runtime has encountered a fatal error. The address of the error
was at 0x6fda02c7, on thread 0x2554. The error code is 0xc0000005.
This error may be a bug in the CLR or in the unsafe or non-verifiable
portions of user code. Common sources of this bug include user
marshaling errors for COM-interop or PInvoke, which may corrupt the
stack.
Is this error from DLL or CLR (.Net)? I never imported any functions from DLL to .Net, so any help is appreciated.
From the unmanaged source:
#define CALL_METHOD __stdcall
And from the managed source:
[DllImport("DVR_NET_SDK.dll", CallingConvention = CallingConvention.Cdecl)]
Your calling conventions do not match.
As for the edit to the question, that is presumably because the C# struct definition does not match the unmanaged struct. You have failed to translate any of the arrays correctly. They will require the use of [MarshalAs(UnmanagedType.ByValArray, SizeConst=...)].
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 have an unmanaged MFC application. I have written a CLI wrapper for the application and converted into a DLL. The unamanged code has string table resources that is used to display messages here and there.
Now I can call the unmanaged code from C# and use the internal logic. But the code errors out when it tries to read a resource string. I hope the resources are not loaded so I tried including a P/invoke LoadLibraryEx from kernel32.dll but still no use. How can I let the unmanaged code use its resource file? Can it do that or it should be modifed??
Thanks.
You can rebuilt MFC using UNICODE strings, declare exported function, whick takes a language id, an ID of the resource string, and return string for that reference ID and locale.
And use it in managed assembly as follows
[DllImport("resource.en-US.dll")]
string GetResourceString(int LANGUAGE_ID, int IID);
And, for example:
try
{
...
}
catch(MyException ex)
{
throw new ApplicationException(GetResourceString(ex.Language, ex.ResourceID), ex)
}
I have a Visual Studio 2008 solution with two projects: a C# Windows Forms application and a C++ DLL. The DLL opens a custom CFileDialog. Here is a toy version that demonstrates the problem, where the C# app is just a button to launch the dialog and a label to show its result:
DialogApp.cs:
...
public partial class Form1 : Form {
...
[DllImport("DialogDll.dll")]
static extern int OpenDialog();
...
private void button1_Click(object sender, EventArgs e) {
int r = OpenDialog();
label1.Text = r.ToString();
}
}
DialogDll.h:
extern "C" {
__declspec(dllexport) int __cdecl OpenDialog();
}
DialogDll.cpp:
#include <afxdlgs.h>
#include "DialogDll.h"
extern int __cdecl OpenDialog() {
CFileDialog d(TRUE, NULL, NULL, OFN_HIDEREADONLY, _T("All Files (*.*)|*.*||"), NULL);
if (d.DoModal() == IFOK) {
return 4;
} else {
return 9;
}
}
When I run this, I get an error about a debug assertion failing, asking to Abort|Retry|Ignore. The assertion is afxCurrentResourceHandle != NULL. How do I get rid of this problem? If I click Ignore, I get my dialog, and everything appears to work fine.
I've already tried following the instructions here:
http://msdn.microsoft.com/en-us/library/7a51wcfx.aspx
These directions say the problem is that a DLL doesn't have a CWinApp object, and I should add AFX_MANAGE_STATE(AfxGetStaticModuleState()) to the beginning of each function call. I did that, and had to resolve a linker issue by following the directions here, manually specifying the entry point for my DLL: http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/0b154e1c-141f-4567-bb24-1ac7c8ee2713/ (The parts about changing the order of the .libs didn't work for me.)
But now I'm getting another error:
LoaderLock was detected:
Attempting managed execution code inside OS Loader Lock. Do not attempt to run
managed code inside a DllMain or image initialization function since doing so
can cause the application to hang.
Good grief! Am I even going in the right direction? I've done years of programming, but I'm pretty new to the Windows platform. I think after all this work, my question is still pretty simple: How do I open a CFileDialog from my dll?
You are probably going in the right direction. I am assuming that you want/need to use MFC in your DLL.
The WinApp and MANAGE_STATE advice was good.
Are you throwing /clr or /clr:pure on any of your C++ source files? Why? Does your C++ DLL mix managed and native code together?
The fix for this trivial app is to not throw /clr. This will make all your C++ code native and ensure that you are not at risk of calling managed static initialisers from the loader lock.
Martyn
Please see comment above, but I would recommend as my answer:
Use System.Windows.Forms.OpenFileDialog instead OR
Use GetOpenFileName