Search code examples
c++visual-c++c++-cliunmanagedmanaged

Use C++ managed Form from unmanaged C++ project


please I need your help, I googled a lot and any answer for this problem....

I have a solution that includes various Unmanaged C++ projects, but now I need to use a Visual C++ Form (that is Managed) into the main unmanaged project, and comunicate with it. It's possible to do it? via wrapper, dll.... how?

I googled a lot but all the cases I found talk about how use Unmanaged into Managed, or are incomplete examples. I found this example and seems that it works, but doesn't compile.

http://www.codeproject.com/Articles/9903/Calling-Managed-Code-from-Unmanaged-Code-and-vice

I'm using Visual Studio 2012.

Thanks a lot.


Solution

  • Finally I found a solution...

    1 - When I want to have the FORM control into non managed code (for create, show, hide, set controls value...) I exported static methods as __declspec(dllexport)

    2 - When I want to send info from FORM to non managed code I do it using callbacks.

    I'm going to explain it....

    Firstly... I create a CLR project as DLL, create a windows Form (MyForm.h) with some controls:

    • 1 exit button
    • 1 button that SEND info TO NON MANAGED code
    • and 1 checkbox that RECEIVE new status FROM NON MANAGED code

    (I ommit the gode generated by visual studio)

    namespace TestUnmanaged {
    ... code ommitted ...
        private: System::Void QuitBtn_Click(System::Object^  sender, System::EventArgs^  e) {
                     this->Close();
                 }
        private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    //Call to non managed function!!!!
                     CallToCallBack();
                 }
        };
    }
    

    Then, I create a static (non managed) class that has a pointer to the form, and manage it's creation, etc..

    //Type of my specific callback function
    typedef std::function<bool (int& _msg)> T_CALLBACK_FUNC;
    
    public class unmanagedClass
    {
    public: 
    
        unmanagedClass();
        ~unmanagedClass();
    
        void CreateForm( void );
    
        HWND getFormHandle(void) const;
        void setCallbackFunction(T_CALLBACK_FUNC _callbackFuntion);
        void callToCallbackFunction(int _value);
        //public for fast tests
        gcroot<TestUnmanaged::MyForm^> p;
    private:
        HWND m_hWnd;
        T_CALLBACK_FUNC m_funcionCallback;
    };
    
    unmanagedClass s_unmanaged;
    

    Here's the .cpp implementation...

    //////////////////////////////////////////////////////////////////////////
    //          Static Functions for DLL_EXPORT
    //////////////////////////////////////////////////////////////////////////
    
    void CloseForm( void )
    {   
        Application::Exit();
    }
    
    void CallToCallBack( void )
    {
        int valor = 5;
        s_unmanaged.callToCallbackFunction(valor);
    }
    
    
    //////////////////////////////////////////////////////////////////////////
    //          Methods for Unmanaged Class
    //////////////////////////////////////////////////////////////////////////
    HWND unmanagedClass::getFormHandle( void ) const
    {
        return m_hWnd;
    }
    
    unmanagedClass::unmanagedClass()
    {
        p = gcnew(TestUnmanaged::MyForm);
    }
    
    unmanagedClass::~unmanagedClass()
    {
        delete (p);
    }
    
    void unmanagedClass::CreateForm( void )
    {
        Application::Run(p);    
    }
    
    void unmanagedClass::setCallbackFunction( T_CALLBACK_FUNC _callbackFuntion )
    {
        m_funcionCallback = _callbackFuntion;
    }
    
    void unmanagedClass::callToCallbackFunction( int _value )
    {
        m_funcionCallback(_value);
    }
    

    Now, I create all the static functions that will be exported as dllexport:

    __declspec(dllexport) void CreateFormDLL(void)
    {
        s_unmanaged.CreateForm();
    }
    
    __declspec(dllexport) void CloseFormDLL(void)
    {
        s_unmanaged.p->Close();
    }
    
    __declspec(dllexport) void ShowFormDLL(void)
    {
        s_unmanaged.p->Show();  
    }
    
    __declspec(dllexport) void HideFormDLL(void)
    {
        s_unmanaged.p->Hide();
    }
    
    __declspec (dllexport) void setCallbackFunctionDLL( T_CALLBACK_FUNC& _doFunction)
    {
        s_unmanaged.setCallbackFunction(_doFunction);
    }
    
    __declspec (dllexport) void setCheckBoxDLL( bool _newValue )
    {
        s_unmanaged.p->getCam01ChkBox()->Checked = _newValue;
    }
    
    __declspec (dllexport) HWND getFormHandleDLL( void )
    {
        return (HWND)s_unmanaged.p->Handle.ToPointer();
    }
    

    Now.... I create the Win32 console App project and link the Managed project. This will be the main process, and the class "ManagedWrapper". Here is the source....

    class ManagedWrapper
    {
    public:
        ManagedWrapper(void);
        ~ManagedWrapper(void);
    
        void init(void);
    
        void createForm(void);
        void showForm(void);
        void closeForm(void);
        void setCam01ChkBox(const bool _newValue);
    private:
        void createFormThread(void);
    
        static bool callBackReceiver(int a);
    };
    
    
    #include "ManagedWrapper.h"
    #include <thread>
    
    __declspec(dllimport) void CreateFormDLL(void);
    __declspec(dllimport) void CloseFormDLL(void);
    __declspec(dllimport) void ShowFormDLL(void);
    __declspec(dllimport) void HideFormDLL(void);
    typedef std::function<bool (int& _msg)> T_CALLBACK_FUNC;
    __declspec (dllimport) void setCallbackFunctionDLL( T_CALLBACK_FUNC& _doFunction);
    __declspec (dllimport) void setCheckBoxDLL( bool _newValue );
    
    ManagedWrapper::ManagedWrapper(void)
    {
    }
    
    ManagedWrapper::~ManagedWrapper(void)
    {
    }
    
    void ManagedWrapper::createForm( void )
    {
        std::thread showThread (&ManagedWrapper::createFormThread, this);
        showThread.detach();
    }
    
    void ManagedWrapper::createFormThread( void )
    {
        CreateFormDLL();
    }
    
    void ManagedWrapper::closeForm( void )
    {
        CloseFormDLL();
    }
    
    void ManagedWrapper::showForm( void )
    {
        ShowFormDLL();
    }
    
    void ManagedWrapper::init( void )
    {
        setCallbackFunctionDLL(T_CALLBACK_FUNC(&ManagedWrapper::callBackReceiver));
    }
    
    bool ManagedWrapper::callBackReceiver( int a )
    {
        printf("Hello world. Parameter value = %d\n",a);
        return true;
    }
    
    void ManagedWrapper::setCam01ChkBox( const bool _newValue )
    {
        setCheckBoxDLL( _newValue );
    }
    

    And finally.... the simplest use from the main(), create the Form, set the checkbox values, if the user click on the button the callback function writes on console... and finally close.

    int _tmain(int argc, _TCHAR* argv[])
    {
        ManagedWrapper umWrap;
        umWrap.init();
        umWrap.createForm();
        system("PAUSE");
        umWrap.setCam01ChkBox(true);
        system("PAUSE");
        umWrap.setCam01ChkBox(false);
        system("PAUSE");
        umWrap.closeForm();
        return 0;
    }
    

    Sorry for the long answer, but I believe that may be usefull for somebody.