Search code examples
c#c++comoffice-interopsmart-pointers

How to return C++ smart pointer to PowerPoint interface using C# Interface


I am making a program partly written in C++ and C#. C# is mainly used for GUI. Inside my C++ code I create PowerPoint COM object and open a presentation in it.

At some point I need to reference PowerPoint::_PresentationPtr in my C# code. To call methods and so on.

PowerPoint::_PresentationPtr is a smart pointer made with

_COM_SMARTPTR_TYPEDEF(_Presentation, __uuidof(_Presentation));

It is defined by Visual studio in msppt.tlh Microsoft.Office.Interop.PowerPoint.dll binding:

struct __declspec(uuid("91493463-5a91-11cf-8700-00aa0060263b"))
/* interface */ PresEvents;
struct /* coclass */ Presentation;

struct __declspec(uuid("9149349d-5a91-11cf-8700-00aa0060263b"))
/* dual interface */ _Presentation;

/* PowerPoint::_PresentationPtr */
_COM_SMARTPTR_TYPEDEF(_Presentation, __uuidof(_Presentation)); 

So it makes PowerPoint::_PresentationPtr for ease of use the COM object in C++, calling methods etc.

And this is C# Microsoft.Office.Interop.PowerPoint.Presentation

namespace Microsoft.Office.Interop.PowerPoint
{
    [CoClass(typeof(PresentationClass))]
    [Guid("9149349D-5A91-11CF-8700-00AA0060263B")]
    public interface Presentation : _Presentation, PresEvents_Event
    {
    }
}

I have an Interface in C# with C++ implementation so I can access it in C# part of the application.

ApplicationHost.cs

namespace SampleWpfUserControlLibrary
{
    public interface IApplicationHostWindow
    {
        void OpenDocument();
        PowerPoint.Presentation GetPresentation();
        void Exit();
    }
}

ApplicastionHost.h

#pragma once
#using <SampleWpfUserControlLibrary.dll>

using namespace SampleWpfUserControlLibrary;

ref class ApplicationHostWrapper : IApplicationHostWindow
{
public:
    ApplicationHostWrapper(CMainFrame * pMainFrame)
    {
        _pMainFrame = pMainFrame;
    }

    virtual void __clrcall Exit() sealed
    {
        _pMainFrame->SendMessage(WM_CLOSE);
    }

    virtual void __clrcall OpenDocument() sealed
    {
        _pMainFrame->OpenDocument();
    }

    virtual PowerPoint::_PresentationPtr __clrcall GetPresentation() sealed
    {
        CMFCBindDoc * pDoc = _pMainFrame->GetDocView()->GetDocument();
        return pDoc->GetPresentation();
    }
};

However it does not compile. Arguing that GetPresentation() is not implemented. As the types do not match.

Update:

What should I return in C++ code PowerPoint::_Presentation or PowerPoint::_PresentationPtr and what should I map it to in C# part? Or How do convert it to Microsoft.Office.Interop.PowerPoint in the C#? I just want to reference it in C#.

These are the errors I get:**

  • Error 3 error C2259: 'ApplicationHostWrapper' : cannot instantiate abstract class
    Source\Application\MainFrm.cpp 146 1 Application
  • Error 1 error C3766: 'ApplicationHostWrapper' must provide an implementation for the interface method
    'Microsoft::Office::Interop::PowerPoint::Presentation
    ^SampleWpfUserControlLibrary::IApplicationHostWindow::getPresentation(void)' source\application\ApplicationHostWrapper.h 39 1 Application

In Object Browser getPresentation() method is this:

unknown-type^ getPresentation() Member of SampleWpfUserControlLibrary::IApplicationHostWindow


Solution

  • Okay, I found solution. in ref class ApplicationHostWrapper : IApplicationHostWindow by calling GetInterfacePtr() on a smart pointer we can get a pointer to interface.

    virtual void* __clrcall GetPresentationPtr() sealed
    {
        CMFCBindDoc * pDoc = _pMainFrame->GetDocView()->GetDocument();
        return (void*)pDoc->GetPresentation().GetInterfacePtr();
    }
    

    In C# Interface declaration ApplicationHost.cs:

    namespace SampleWpfUserControlLibrary
    {
        public interface IApplicationHostWindow
        {
            void OpenDocument();
            unsafe void* GetPresentationPtr();
            void Exit();
        }
    }
    

    And this allows us to make a method in managed code for example in a class:

    private IApplicationHostWindow _hostWindow;
    unsafe private PowerPoint.Presentation getPresentation(){
       IntPtr preIntPtr = new IntPtr(_hostWindow.GetPresentationPtr());
       return (PowerPoint.Presentation)Marshal.GetUniqueObjectForIUnknown(preIntPtr);
    }
    

    The only drawback is that it requires using /unsafe for compilation. And what could be the consequences I have no idea yet. If someone knows how to overcome /unsafe and do it differently you are welcome.