Tech Off Thread

22 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

Mixing Managed and Unmanaged C++ in a DLL

Back to Forum: Tech Off
  • User profile image
    brussell

    I need to write a Managed C++ DLL that appears as a Win32 DLL to a program.

    I can get the DLL to be recognized by the program, but I'm having a lot of problems trying to add in Managed C++.

    Can anyone point me to something with an example or information on how to write a DLL that uses Managed and unmanaged C++?

    I keep getting compiler errors or crashes during debug. I can't get it to work right. I don't know if I'm just not setting the project up correctly or if I'm coding it up wrong. I haven't been able to find any reference that helps me to do this, but I'm sure there must be something.

  • User profile image
    brussell

    Here is some more information if it will help:

    I'd like to have one DLL.

    I have a .def file that has the functions to be used by a program.
    I have a .cpp file that will have those functions
    I have a .h that defines those functions
    This needs to appear to be a Win32 DLL to the program.


    I now need to add functions that are capable of using .NET to send information to a server.
    I also need functions that look at the hardware to get this information.

    Any ideas?

    I may be getting close. The error I am getting right now is:
    error C3604: 'System::Management::ManagementObjectSearcher': can only create a __gc type object on the __gc heap

  • User profile image
    Sven Groot

    brussell wrote:
    Here is some more information if it will help:

    I'd like to have one DLL.

    I have a .def file that has the functions to be used by a program.
    I have a .cpp file that will have those functions
    I have a .h that defines those functions
    This needs to appear to be a Win32 DLL to the program.


    I now need to add functions that are capable of using .NET to send information to a server.
    I also need functions that look at the hardware to get this information.

    Any ideas?

    I may be getting close. The error I am getting right now is:
    error C3604: 'System::Management::ManagementObjectSearcher': can only create a __gc type object on the __gc heap

    Could I see the line of code that causes that error message?

  • User profile image
    brussell

    Sven Groot wrote:

    Could I see the line of code that causes that error message?


    #pragma managed
    System::String* find_hardware( String * s )

    {
       System::Management::ManagementObjectSearcher* searcher;
       System::String* sProc = CString("select * from WIN32_Processor");
       //The line below this comment is the one with the error message
       searcher = System::Management::ManagementObjectSearcher( sProc );
       System::Management::ManagementObjectCollection* objCol = searcher->Get();
       System::Management::ManagementObjectCollection::ManagementObjectEnumerator* objEnum = objCol->GetEnumerator();
       System::Management::ManagementBaseObject* objBase = objEnum->get_Current();

       return CString( objBase->GetText(System::Management::TextFormat::Mof) );
    }

    #pragma unmanaged
    /*
       All my functions that are exposed to the program that needs a Win32 DLL
    */

    Edit: I'm not really going to use the find_hardware() as it currently is. It is mainly just a test of combining un/Managed C++. I need to find a way to get some hardware IDs and check a sever for rights.

  • User profile image
    Sven Groot

    Question 1: What's CString()? I'm only familiar with one CString and it's from MFC, you shouldn't be using it with Managed C++.

    This line:
    System::String* sProc = CString("select * from WIN32_Processor");
    Becomes:
    System::String* sProc = S"select * from WIN32_Processor";

    And just remove the whole CString bit from the return statement.

    As for the error message, you forgot a new:
    searcher = new System::Management::ManagementObjectSearcher( sProc );

  • User profile image
    brussell

    Ah, sorry, you're right. I was combining code that I shouldn't have been.

    I must have opened the wrong example since I have made those modifications in a different attempt and that's where I got the error message above.

    So, my question is still the same, but your code is what is used in that project that gets the error.

    Edit: Sorry for the confusion, it's just that I have created many different projects and different blocks of code. I have tried using different settings with very basic blocks of code. Just trying to create a String (I believe that's what I tried) got me the same error about creating a __gc object.
    Could the error be because I'm trying to mix managed an unmanaged on the same thread? I have seen program examples and they don't seem to use seperate threads for the different sections of code

  • User profile image
    Sven Groot

    I'm going to need to see the code that gives the error. The code with my modifications compiles fine here, and for all intents and purposes should work fine.

    Threads have nothing to do with it. You can mix-and-match managed and unmanaged as you see fit. The only restriction is that you cannot call into managed code from DllMain.

  • User profile image
    brussell

    I'm using Visual Studio 2003. What version are you using?

    I have tried an MFC DLL (and then turn on Managed Extensions) and I've tried using a .NET Class and a couple other project types.
    What project type and settings do you use?

    I have just made my .cpp contain only:


    #include "stdafx.h"

    using namespace System;

    using namespace System::Xml;

    using namespace System::Security::Principal;

    System::String* find_hardware( String * s )

    {

    System::Management::ManagementObjectSearcher* searcher;

    System::String* sProc = S"select * from WIN32_Processor";

    searcher = System::Management::ManagementObjectSearcher( sProc );

    System::Management::ManagementObjectCollection* objCol = searcher->Get();

    System::Management::ManagementObjectCollection::ManagementObjectEnumerator* objEnum = objCol->GetEnumerator();

    System::Management::ManagementBaseObject* objBase = objEnum->get_Current();

    return CString( objBase->GetText(System::Management::TextFormat::Mof) );

    }

    That still gets me the same error about __Gc object

  • User profile image
    Sven Groot

    You're still missing a new:
    searcher = new System::Management::ManagementObjectSearcher( sProc );

    Put that in there and it should work fine.
    And remove the CString bit from the last line:

    Full code:

    System::String* find_hardware( String * s ) 
    {
    System::Management::ManagementObjectSearcher* searcher;
    System::String* sProc = S"select * from WIN32_Processor";
    searcher = new System::Management::ManagementObjectSearcher( sProc );
    System::Management::ManagementObjectCollection* objCol = searcher->Get();
    System::Management::ManagementObjectCollection::ManagementObjectEnumerator* objEnum = objCol->GetEnumerator();
    System::Management::ManagementBaseObject* objBase = objEnum->get_Current();
    return objBase->GetText(System::Management::TextFormat::Mof);
    }


    That should compile fine.

  • User profile image
    brussell

    You're right. I put that back in there (somehow I lost it during one of my changes due to another error).

    I was getting an error about placement arguments not allowed while creating instance of managed classes with the code you sent me (which I was getting the error before, and when I retyped it, accidently leaving out the new, I got the other error message). Apparently, that message was coming from this code (I commented everything out, it compiled and I started uncommenting blocks until I saw the error again):

    #ifdef _DEBUG

    #define new DEBUG_NEW

    #endif


    So I removed that from the code (Not even sure what that does or means, but it was put in there by one of the projects I created) and it compiles fine now.
    It even runs in debug mode without crashing now! Thanks a ton! (Now before I get too excited again, I need to make sure the managed code will work right Smiley )

  • User profile image
    brussell

    Darn, new problem. I guess I can't call managed functions from unmanaged functions?

    How do I, on load of the DLL, have it start doing some managed code while allowing it to have the unmanaged functions get called by the program running it?

  • User profile image
    Sven Groot

    Just remove the #pragma unmanaged. You can still export the functions without it, and call into managed code.

    Like I said, the only restriction is on using managed code from DllMain. For other functions you don't need to do anything special, not even the #pragma unmanaged is needed.

  • User profile image
    brussell

    It feels like I'm getting closer.... but I just keep running into another problem Smiley

    If I have the #pragma managed and unmanaged in there, the DLL works great in my program. I can debug with no crashing. However, I still can't seem to unload/load my DLL in the program
    Downside, I can't call managed functions from unmanaged functions.

    If I take the pragmas out, I get a crash when the DLL loads and I'm debugging.
    If I do this line in an unmanaged function, my program crashes. (I can't debug it because VS crashes as soon as the DLL loads if the debugger is attached)

    CString sTemp = find_hardware( "WIN32_Processor" );


     

  • User profile image
    Sven Groot

    I'm afraid I can't help you based on this info. If you could give me a complete, compilable example that exhibits the problem maybe I can do more.

    Only thing I can think of is you're assigning a System::String* to a CString, not so sure that's safe. I've never tried to mix MFC with Managed C++, so I'm not sure.

  • User profile image
    brussell

    I just realized something... The little test harness program I was running the DLL in doesn't start .NET.
    I'm sure that's going to be a problem.

    Edit: I'm getting System.InvalidOperationException and I'm guessing that is why.

    I tried it in the actual program the DLL will be running in (It is supposed to start .NET) and I get the same error/crash.
    If this error is from not having .NET, maybe the .NET in the program isn't getting started soon enough or correctly?

  • User profile image
    brussell

    Sven Groot wrote:
    I'm afraid I can't help you based on this info. If you could give me a complete, compilable example that exhibits the problem maybe I can do more.

    Only thing I can think of is you're assigning a System::String* to a CString, not so sure that's safe. I've never tried to mix MFC with Managed C++, so I'm not sure.


    What is something safer to assign it to in unmanaged code?

  • User profile image
    Sven Groot

    You're getting an InvalidOperationException because you're calling get_Current on an enumerator before calling MoveNext, which is not allowed.

    I put together an example, that shows how to use the Marshal class to convert a System::String to a char*. It consists of an unmanaged application that calls into a managed dll, the way you described above, using your find_hardware function. It works fine on my system. Get it here. I hope it helps.

  • User profile image
    brussell

    Sorry to keep on asking, but thank you so very much for all the help.
    I'm sure this would be easier if I was more familiar with mixing managed and unmanaged or could even just be able to debug so I could see what is going on...

    Your sample works great and it has got me even closer to working.

    I added the exported_function() in order to get a char* back.
    I can now do this without any problems:

    char* sTest = exported_function();

    Unfortunately, if I add this line after it to see the value, it crashes when it runs it:
    strncpy(a_psDLLDef_szCopyright, sTest, sizeof(a_psDLLDef_szCopyright)-1 );

    I have also tried replacing those two lines with:
    const char* sTest = exported_function();
    char* sTemp = "";
    strncpy( sTemp, sTest, sizeof(sTemp)-1 );

    I'm not really familiar with strncpy... is that not safe either?
    The crash I get now doesn't show any exceptions or anything. It's the basic "<prog name> has encountered a problem and needs to close"

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.