locked
DllExport as opposed to DllImport in C# RRS feed

  • General discussion

  • I am working on a C# 3.5 plugin that is used by an unmanaged C++ host application. This C++ application is a 3rd party commercial application and I don't have the source code to it.

    Anyway, I have the plugin working using a managed C++ helper DLL that handles all of the unmanaged to managed API calls. My plugin has a managed UI that is embedded into a native window that is supplied by the unmanaged application. I use NativeWindow to do this.

    But now I have run into a problem where I can't get Drag & Drop to work. This has something to do with COM not being initialized or something, and I am looking at ways to solve this.

    Anyway, that is not the main reason I'm here (although it would be great if someone could give me some advice). I heard rumors that there could be an easier way to do something like this in C# 4.0. Is this true? Ideally, it would be something like:

    [DllExport]
    private static void MyMethod(...)
    {
        ...
    }

    So what happens is that the method is exported so that it becomes visible as a C entry point using the same marshalling features that DllImport gives you. This way I can write my plugin as a single C# DLL that exposes C entry points. Hopefully it will also do proper COM initialization etc.

    Does anyone know if something like this is forthcoming in C# 4.0?

    • Changed type nobugz Wednesday, October 7, 2009 3:27 PM found wrong place to get an answer
    Tuesday, October 6, 2009 6:21 AM

All replies

  • It's simply not possible to export a dll, simply because managed assemblies do not have a way to import a method at a specific address. What you need to do is create a COM-visible class. Then, you can create an instance of the type (COM-visible) and then call the methods on the object from unmanaged code.

    Also, see the threads below:

    Thread 1
    Thread 2 (last post)
    Geert van Horrik - CatenaLogic
    Visit my blog: http://blog.catenalogic.com

    Looking for a way to deploy your updates to all your clients? Try Updater!
    Tuesday, October 6, 2009 8:14 AM
  • It is possible in the C++/CLI language.  You can declare static functions with the __declspec(dllexport) declarator that invoke a managed method.  The compiler automatically creates the entry point stub that's needed to ensure that the CLR is loaded when the client code calls it and makes the unmanaged-to-managed transition.  This isn't cheap, you should prefer COM interop when possible.

    The Drag + Drop issue is most likely a COM initialization problem.  You can't really control this, it is the unmanaged app that called CoInitialize().  D+D requires the UI thread to run as a STA that pumps a message loop.  Fixing this is ugly, you'd have to create your own STA thread.  That makes interop with the unmanaged app pretty tricky.

    Hans Passant.
    Tuesday, October 6, 2009 1:26 PM
  • Thanks for the replies so far, but I think I need to clarify some of my initial points:

    1) I can't use COM simply because the 3rd party app I am writing the plugin for uses a simple C API. I can't change it. So I am already using a managed C++ helper DLL that calls into my managed C# DLL. This already works. My main question was whether .Net 4.0 is going to add new features that makes this more seamless. I don't think there is a technical reason why exporting C style functions from a C# DLL should not be possible - it seems it is a question of extending C# to do what managed C++ already can do.  In addition, you can already create a C style function pointer that calls into a managed method using Marshal.GetFunctionPointerForDelegate. I use it all the time, except in this case I can't because I need to export the function.  I don't think it would be too hard to add some glue code into .Net that can do this all behind the scenes and then export C functions for methods with attribute [DllExport]. It just seems like a really useful feature that would make scenarios like this easier. Especially with the side-by-side .Net support, it seems that writing plugins in managed code for unmanaged hosts should be made more seamless.

    2) About my managed plugin... I checked the thread that calls into my managed code, and it is already an STA thread. I'm just wondering what would the easiest way be to get D+D to work in this case.
    Tuesday, October 6, 2009 3:40 PM
  • To be clear: allowing unmanaged hosts to use managed code is already quite seamless.  The CLR hosting interfaces are quite clean.  But that's not going to work if you can't change the host or you can't write COM code.  The C# compiler generates 100% managed code and that code needs the CLR to execute.  The pixie dust you are looking for does not exist.

    Hans Passant.
    Tuesday, October 6, 2009 7:08 PM
  • To be clear: allowing unmanaged hosts to use managed code is already quite seamless.  The CLR hosting interfaces are quite clean.  But that's not going to work if you can't change the host or you can't write COM code.  The C# compiler generates 100% managed code and that code needs the CLR to execute.  The pixie dust you are looking for does not exist.

    Hans Passant.

    I guess you missed my main point.

    "But that's not going to work if you can't change the host or you can't write COM code."

    As I already said, everything is already working (without using COM, just straight C calls), except for the D+D part. So I am already 95% there. There are ways to hack it so that D+D can work, I'm just wondering if .Net 4.0 is going to make any of this easier.

    You make it sound as if what I already have working right now is impossible because "The C# compiler generates 100% managed code and that code needs the CLR to execute".
    Tuesday, October 6, 2009 9:33 PM
  • I tried to explain my project as well as I could, but it seems it wasn't clear enough.

    I already have a managed C++ DLL, which in turn loads my managed C# DLL.  So basically:

    Unamanged host <-> Managed C++ DLL <-> Managed C# DLL

    So some of the comments in the tread seems like none of what I am doing is going to work. Of course the CLR is being loaded (via the managed C++ DLL), how else would my C# code even run?

    The other part of my post was pointing out that it would be a nice addition if C# supported exporting methods. All the building blocks are already there. .Net is very good at marshalling between C <-> C#, but this only goes one way.

    If you add support to do something like:

    [DllExport]
    private static void MyMethod(...)
    {
        ...
    }

    The compiler can then generate the C stub so that it checks whether CLR is loaded, and load it if it isn't. It seems that this is how managed C++ aready works. So why not take it a step further and make it even more seamless?

    BTW, the C API I am using is an industry standard plugin API, so it isn't as if I can request that they drop it and start using COM.

    Tuesday, October 6, 2009 10:14 PM
  • This is what I have been looking for:

    http://www.codeproject.com/KB/dotnet/DllExporter.aspx

    "When the resulting DLL is loaded by unmanaged executable, CLR will be initialized and will replace reserved RVA entries with actual addresses. Exported function calls will be intercepted by CLR and corresponding managed code will be executed."

    If this guy can do it, why can't MS?

    Wednesday, October 7, 2009 5:36 AM
  • It is possible in the C++/CLI language.  You can declare static functions with the __declspec(dllexport) declarator that invoke a managed method.  The compiler automatically creates the entry point stub that's needed to ensure that the CLR is loaded when the client code calls it and makes the unmanaged-to-managed transition.  This isn't cheap, you should prefer COM interop when possible.


    Hans Passant.
    Wednesday, October 7, 2009 7:36 AM
  • It is possible in the C++/CLI language.  You can declare static functions with the __declspec(dllexport) declarator that invoke a managed method.  The compiler automatically creates the entry point stub that's needed to ensure that the CLR is loaded when the client code calls it and makes the unmanaged-to-managed transition.  This isn't cheap, you should prefer COM interop when possible.


    Hans Passant.

    Hans,

    Sorry, I don't understand the point you are making. I am not saying it isn't possible using managed C++, in fact I already said that this is how I am doing it right now. In my case I clearly cannot use COM as the commercial host I am writing the plugin for is using an industry standard C API. There are thousands of plugins following this C API so I can't ask everyone to switch to COM.

    And in the link I provided (http://www.codeproject.com/KB/dotnet/DllExporter.aspx), there is clearly a way to do exactly what I described. The author even uses his own custom DllExport attribute that you add to any managed C# static method to export it as a C entry point in the same DLL, with no intermediate managed C++ DLL required. So I believe my original point is very valid in that I think if MS adds this functionality natively (just like they do for regular P/Invoke) it would make scenarios like what I am describing much more seamless. You say it is seamless but right now it is only seamless if you want to call into unmanaged code from managed code, or if you can use COM. For my particular scenario, what MS provides is anything but seamless (requiring an intermediate managed C++ DLL).
    Wednesday, October 7, 2009 7:59 AM
  • Hmm, requiring a custom tool that you need to run *every* single time the C# code is recompiled isn't something I'd call seamless.  The failure mode when you forget isn't pretty.  Not sure why you'd keep going on about this, use it if it fits your need.

    Hans Passant.
    Wednesday, October 7, 2009 8:11 AM
  • Hmm, requiring a custom tool that you need to run *every* single time the C# code is recompiled isn't something I'd call seamless.  The failure mode when you forget isn't pretty.  Not sure why you'd keep going on about this, use it if it fits your need.

    Hans Passant.

    I don't have to remember to do anything:

    "To run DllExporter after each build, you can go to Visual Studio -> Project Properties -> Build Events and add the following post-build commands..."

    How is that not seamless?

    Seriously, why are you people so close-minded? Obviously this is a useful feature because people won't be making work-arounds for this if it wasn't.  And my original question about whether .Net 4.0 makes any of this easier is still unanswered.

    I guess this is not a place to get answers...
    Wednesday, October 7, 2009 3:04 PM
  • There are other concerns that need to be taken into account.

    For example, if someone else writes a managed plugin for the same (unmanaged) program that uses a different version of the CLR... The CLR is a platform, not a library; best case is that you'll end up with two complete CLRs in the same process, but I believe that any pre-4.0 CLRs will conflict and cause an error.

    Microsoft could make it simple if they wanted to, but that would give the illusion that this is supported.

    An alternative design is to create an unmanaged plugin DLL that starts a managed process and handles communication back and forth between the managed process and the host process. This architecture is supported.

           -Steve
    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ


    Microsoft Certified Professional Developer
    Wednesday, October 7, 2009 3:35 PM
  • There are other concerns that need to be taken into account.

    For example, if someone else writes a managed plugin for the same (unmanaged) program that uses a different version of the CLR... The CLR is a platform, not a library; best case is that you'll end up with two complete CLRs in the same process, but I believe that any pre-4.0 CLRs will conflict and cause an error.

    Microsoft could make it simple if they wanted to, but that would give the illusion that this is supported.

    An alternative design is to create an unmanaged plugin DLL that starts a managed process and handles communication back and forth between the managed process and the host process. This architecture is supported.

           -Steve
    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ


    Microsoft Certified Professional Developer

    Steve,

    Thanks for the reply. Right now the project I am developing is only for my own use, so the scenario where more than one CLR versions are loaded at the same time is not currently a problem for me since I have a controlled environment. Once I can use 4.0 I will do so in which case this will not be an issue any more.

    I have read a few times that with 4.0, MS is supporting the scenario for writing managed plugins for unmanaged code. This is why I asked about any additional support that 4.0 provides in this specific area (ie, something similar to DllExport). It would be a bit strange if MS changes their recommendations that with 4.0 it is now acceptable to create such plugins, but at the same time still require an intermediate managed C++ DLL.
    Wednesday, October 7, 2009 3:46 PM