2
votes

We have two C++/CLI projects, a pure CLR project and a mixed-mode project that exists to provide our unmanaged codebase access to the pure CLR project. We are having trouble getting the mixed-mode project to see symbols defined in the pure CLR project.

Specifically we have a form, call it MainForm, defined in the purely-managed project. It's a typical C++/CLI Windows Form:

MainForm.h:

public ref class MainForm : public System::Windows::Forms::Form
{
public:
    MainForm(void)
    {
        InitializeComponent();
        //
        //TODO: Add the constructor code here

    }
    ...
};

Our mixed-mode "wrapper" project tries to use it, like so:

ManagedDialogProvider.h:

namespace ManagedWrapper
{
    public ref class ManagedDialogProvider
    {
        static void ShowDialog()
        {
             OurManagedComponents::MainForm^ form = gcnew OurManagedComponents::MainForm();
        }
    };
}

(We then have a C++/MFC class in the mixed-mode project, CManagedDialogProvider, that calls ManagedDialogProvider so that our unmanaged code can use it. The error isn't occurring there, however.)

When I try building the mixed-mode project, it tells me that MainForm is not a member of OurManagedComponents. (Error in ManagedWrapper::ManagedDialogProvider::ShowDialog().)

Notes:

  • The mixed-mode project has a reference to the managed project.
  • I have tried using an #include at the top of the managed wrapper class instead of a reference, and while this compiled, I then couldn't load the form due to its resources not being found. I backed out of this solution as it's not accepted practice if I understand correctly; .NET projects should reference each other via assembly references only.
  • I've verified that the managed class is accessible (public).
  • I've checked the Object Browser to ensure that OurManagedComponents is visible and contains MainForm.

Any ideas? The same mixed-mode project has no trouble wrapping C# managed components, but when I tried using that same approach for this C++/CLI managed component, these issues appeared.

3
As the error is about OurManagedComponents::MainForm you should probably post a reduced version of the class.Daniel Earwicker
Also please give more information about CMainDialogProvider.ali_bahoo
Updated example--thanks!System.Cats.Lol
Use Object Browser to verify that the class is visible and that you used the right namespace name. Consider an oops like OurManagedComponents::OurManagedComponents::MainForm. Double-check with, say, a C# project.Hans Passant
@Hans: Browsing objects by namespace, and I see {} OurManagedComponents, and inside that MainForm as a publicly-accessible class, and inside that, a public constructor. The intellisense suggests I'm using the right object as well--it was able to autocomplete the OurManagedComponents::MainForm. But then I build and it says MainForm isn't a member of OurManagedComponents. :(System.Cats.Lol

3 Answers

2
votes

It turned out that OurManagedComponents::MainForm had no implementation file (.cpp); it only had a .h file. So naturally, MainForm was never actually built or linked in to the project. (Interestingly, the object browser still showed OurManagedComponents::MainForm and the project still built just fine; it must see declared types regardless of whether they are implemented). What can I say, I've been using C# too long :-)

Once I created a MainForm.cpp (empty but for include "MainForm.h") and rebuilt, everything worked.

0
votes

Try:

ManagedWrapper::ManagedDialogProvider::ShowDialog();
0
votes

We then have an unmanaged class in that same project that calls ManagedDialogProvider so that our unmanaged code can use it.

Unmanaged (native) code can not reach to managed code without proper callbacks.
Think about the code below.

// CMainDialogProvider.h

typedef void (*ShowDialogNativeCB)() ;

class CMainDialogProvider
{
//..
public:
  ShowDialogNativeCB nativeCB;
//..

}

// ManagedDialogProvider.h
#include "CMainDialogProvider.h"

public delegate void ShowDialogClrCB ();

namespace ManagedWrapper
{
   // ....
   //somehow you have to provide the ShowDialog() function as a callback;
   ShowDialogClrCB ^ clrCB = gcnew ShowDialogClrCB(&ManagedDialogProvider::ShowDialog());
   GCHandle clrCBhandle = GCHandle::Alloc(clrCB);
   // to prevent the garbage collection of delegate.
   // but this must be freed later. 
   IntPtr ip = Marshal::GetFunctionPointerForDelegate(clrCB);
   // Lets say Instance is an instance of CMainDialogProvider.
   Instance->nativeCB = static_cast<ShowDialogNativeCB>(ip.ToPointer());
   //...
}

#include "stdafx.h"
#include "CManagedDialogProvider.h" // C++ class
#include "ManagedDialogProvider.h"  // .NET ref class

IMPLEMENT_DYNAMIC(CManagedDialogProvider, CObject)

void CManagedDialogProvider::ShowDialog()
{
   if(nativeCB != NULL)
     nativeCB();
}