Asked  2 Years ago    Answers:  5   Viewed   837 times

I composed .Net 3.5 dll with single method, which is to be called by Delphi .exe. Unfortunately it does not work.

The steps: 1. Create C# 3.5 dll with the code:

public class MyDllClass
{
    public static int MyDllMethod(int i)
    {
        MessageBox.Show("The number is " + i.ToString());
    }
}
  1. Go to Assembly Properties --> Assembly Information and checked the "Make Assembly COM-Visible"
  2. Used RegAsm.exe to register my dll

This throws Delphi exception which indicates it cannot connect the dll. What are the steps required to enabled usage of C# managed dll from unmanaged code.

Does any one familiar with good example about the subject?

Thank you

 Answers

5

After massive investigation I found the solution: it's all about registration parameters. The flag /codebase must be added to the regasm command.

Many posts out there suggest to use Guid and other COM attributes on the C# Com exposed object, I managed to deliver COM functionality using the ComVisible(true) attribute and regasm /tlb /codebse command.

The code:

[Guid("7DEE7A79-C1C6-41E0-9989-582D97E0D9F2")]
[ComVisible(true)]
public class ServicesTester
{
    public ServicesTester()
    {
    }

    //[ComVisible(true)]
    public void TestMethod()
    {
        MessageBox.Show("You are in TestMEthod Function");
    }
}

and as I mentioned I used regasm.exe /tlb /codebase to register it

Saturday, December 10, 2022
1

I found the reason for my failed attempts by utilising a tool called; Microsoft(R) P/Invoke Interop Assistant as suggested by an answer on this thread.

I utilised this tool to input some of the C function prototypes and get it to generate the required C# prototype on my behalf. The C prototype looked like the following;

long __stdcall TransProjPt(LPSTR psGridFile, long lDirection, double dEasting, double
dNorthing, long lZone, double* pdEastNew, double* pdNorthNew, double* pdEastAcc,
double* pdNorthAcc) 

When entering this into the Interop assistant tool, it showed that rather than using longs (as I had done in my original question), these should be declared as an int. It produced the following output that meant my code above now worked as I'd hoped. Yay.

    /// Return Type: int
    ///psGridFile: LPSTR->CHAR*
    ///lDirection: int
    ///dEasting: double
    ///dNorthing: double
    ///lZone: int
    ///pdEastNew: double*
    ///pdNorthNew: double*
    ///pdEastAcc: double*
    ///pdNorthAcc: double*
    [System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="TransProjPt", CallingConvention=System.Runtime.InteropServices.CallingConvention.StdCall)]
public static extern  int TransProjPt([System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] System.Text.StringBuilder psGridFile, int lDirection, double dEasting, double dNorthing, int lZone, ref double pdEastNew, ref double pdNorthNew, ref double pdEastAcc, ref double pdNorthAcc) ;

Thanks for everyones help with this.

Wednesday, December 14, 2022
 
5

The best way in my opinion is to crate a C++/CLI lib that you can use to communicate between the layers.

This 3rd party library will be compiled with /clr enabled.

Then you can use the header definitions to the proper c++ function wrappers to call the C# functions.

C++/CLI can help you manage the call just the way you want it, and let you design the type casts the way you want them.

Wednesday, November 30, 2022
5

If you are on .NET 4.0, you can use theAppDomain.FirstChanceExceptionevent to get notification of exceptions.

Saturday, August 13, 2022
 
pagemag
 
3

In .NET, type initializers may only be called the first time a field is accessed. This is controlled by the [BeforeFieldInit] attribute.

I filed a bug report, which is only available to beta testers, despite being marked "Public".

Here's the explanation from Microsoft, which you may find helpful:

For C++, this is the intended behavior. We mark our classes with BeforeFieldInit, and so the initialization the CLR is performing is correct. We do not offer a way in C++/CLI to change this behavior. If you require the class constructor to run, you are able to call System.Runtime.CompilerServices.RuntimeHelpers::RunClassConstructor explicitly.


Since we're invoking the standard here, the line from Partition I, 8.9.5 says this:

If marked BeforeFieldInit then the type’s initializer method is executed at, or sometime before, first access to any static field defined for that type.

That section actually goes into detail about how a language implementation can choose to prevent the behavior you're describing. C++/CLI chooses not to, rather they allow the programmer to do so if they wish.

Basically, since the code below has absolutely no static fields, the JIT is completely correct in simply not invoking static class constructors.

Thursday, October 13, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 

Browse Other Code Languages