Pages: 1
Print
Author Topic: Interacting with running XMAX  (Read 483 times)
elias
Member

Posts: 13


« on: July 08, 2011, 06:02:43 AM »

Hello!
I use XMAX 6.0 and Visual Studio 2003.
How can I connect my Visual C++ plugin (another ActiveX object with MFC support) with the running instance of XMAX? I've generated COleDispatchDriver wrappers, added XMAX to the ROT. My plugin is loaded in the On_Macro_File_Load handler (VBScript).
The sample written in Delphi has successfully called XMAX 'ShowAbout' method (VB .NET demo XMActiveX_VBSample.exe serves a XMAX container).
But the problem is linked with QueryInterface within my plugin. I can't get XMAX interface (which contains ShowAbout method), only IID_IDispatch is available.

Code:
LPDISPATCH pDisp;
GUID guid;
HRESULT res = 0;
res = ::CLSIDFromProgID(L"XMetaL.Control", &clsid);
if (res != S_OK)
 AfxMessageBox(L"CLSIDFromProgID fail");
res = ::GetActiveObject(clsid, NULL, &pUnk);
if (res != S_OK)
{
AfxMessageBox(L"GetActiveObject fail");
return S_FALSE;
}
res = ::IIDFromString( L"{A41FC757-7E7D-4299-943D-DCEC8E966348}", &guid);
if (res != S_OK)
AfxMessageBox(L"IIDFromString fail");
VERIFY(pUnk->QueryInterface(guid,(void**) &pDisp) == S_OK); //<--fails here

I've looked up this guid in the OLE/COM Object Viewer (it's a standard tool within Microsoft Visual Studio).
Logged
XMetaLOldTimer
Global Moderator
Member

Posts: 19


« Reply #1 on: July 08, 2011, 02:05:00 PM »

What is the HRESULT on the line that fails?  E_NOINTERFACE?  If so, then I have to question the code that added the COM interface to the ROT.  What does that code look like?  

How do you get ahold of an IXMetaLControl interface instance to setup your COleDispatchDriver wrapper? There is no way to obtain that XMAX interface from within the scope of a macro (unless you write some container code to inject it).  The top-level COM objects available from within a macro are ActiveDocument and Selection.  But, neither of those objects let you get ahold of an IXMetaLControl instance.

BTW, calling methods on the IXMetaLControl interface from with the scope of a macro is ill advised.
« Last Edit: July 08, 2011, 02:31:36 PM by XMetaLOldTimer » Logged

Addam Smith, XMetaL Project Lead & Architect
JustSystems Canada Inc.
elias
Member

Posts: 13


« Reply #2 on: July 11, 2011, 12:22:14 AM »

I've got  E_NOINTERFACE error.
Here is a fragment of VB .NET code of the container app:
Code:

<DllImport("oleaut32.dll", EntryPoint:="RegisterActiveObject")> _
     Public Shared Function RegisterActiveObject(<MarshalAs(UnmanagedType.IUnknown)> ByVal punk As Object, ByRef rclsid As Guid, ByVal dwFlags As Integer, ByRef pdwRegister As Integer) As Integer
    End Function
    <DllImport("oleaut32.dll", EntryPoint:="RevokeActiveObject")> _
    Public Shared Function RevokeActiveObject(ByVal pdwRegister As Integer, ByVal pvReserved As Integer) As Integer
    End Function

Public Function Register_OLE32(ByVal itemname As String, ByRef obj As Object) As Integer
        Dim enc As New UnicodeEncoding
        Dim errorcode As Integer
        Dim guid As New Guid
        Dim registered As Integer
        Dim item As Byte() = enc.GetBytes(itemname)

        errorcode = CLSIDFromString(item, guid)
        Marshal.ThrowExceptionForHR(errorcode)
        'ACTIVEOBJECT_WEAK is 1
        errorcode = RegisterActiveObject(obj, guid, 1, registered)
        Marshal.ThrowExceptionForHR(errorcode)
        Return registered
    End Function

    Public Sub Unregister_OLE32(ByVal id As Integer)
        RevokeActiveObject(id, 0)
    End Sub

    <DllImport("ole32.dll", EntryPoint:="CLSIDFromString")> _
         Public Shared Function CLSIDFromString(ByVal lpszCLSID As Byte(), ByRef pclsid As Guid) As Integer
    End Function
 Private xmaxROTid As Integer

Private Sub XMActiveX_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.FindReplaceDlg = New FindReplaceForm()
        Me.FindReplaceDlg.SetXMetaLActiveX(Me.AxXMetaLControl) ' FindReplaceDlg needs to know which XMetaL Control to Find and Replace, etc

        Me.ValidationErrorDlg = New ValidationForm()
        Me.ValidationErrorDlg.SetXMetaLActiveX(Me.AxXMetaLControl)
        xmaxROTid = Register_OLE32("XMetaL.Control", Me.AxXMetaLControl)     
    End Sub

Private Sub XMActiveX_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
        Unregister_OLE32(xmaxROTid)       
    End Sub
I am not trying to get the IXMetaLControl instance within macros. I create my plugin instance via CreateObject call in the On_Macro_File_Load handler. In the FinalConstruct method (C++ project) of the plugin I try to get  the IXMetaLControl instance.
Logged
elias
Member

Posts: 13


« Reply #3 on: July 11, 2011, 05:06:57 AM »

If we can't get the running XMAX instance within C++ plugin then should I create some public plugin methods which will be called within macros and transfer handles to objects like ActiveDocument?
I mean something like
STDMETHODIMP CMyPlugin::AttachActiveDoc (IDispatch* pDoc);

But what if I'd like to get window handle of XMAX - ActiveDocument, Selection are useless in this case...
Thus only container app can easily get the XMAX window handle.   
« Last Edit: July 11, 2011, 06:26:01 AM by elias » Logged
XMetaLOldTimer
Global Moderator
Member

Posts: 19


« Reply #4 on: July 11, 2011, 03:32:49 PM »

Quote
Code:
   
xmaxROTid = Register_OLE32("XMetaL.Control", Me.AxXMetaLControl)  // BAD ASSUMPTION IS HERE    

"Me.AxXMetaLControl" is some .NET COM-callable wrapper object around XMAX.  It is not an object with an IXMetaLControl interface you can query directly.  So, that is why you get E_NOINTERFACE HRESULT.


Quote
I am not trying to get the IXMetaLControl instance within macros. I create my plugin instance via CreateObject call in the On_Macro_File_Load handler. In the FinalConstruct method (C++ project) of the plugin I try to get  the IXMetaLControl instance.

I am not so sure about that.  Think about the call-stack...isn't FinalConstruct executed within the scope of On_Macro_File_Load?  Either way, it is not a big deal.

« Last Edit: July 11, 2011, 03:35:07 PM by XMetaLOldTimer » Logged

Addam Smith, XMetaL Project Lead & Architect
JustSystems Canada Inc.
XMetaLOldTimer
Global Moderator
Member

Posts: 19


« Reply #5 on: July 11, 2011, 03:49:11 PM »

...should I create some public plugin methods which will be called within macros and transfer handles to objects like ActiveDocument?
I mean something like
STDMETHODIMP CMyPlugin::AttachActiveDoc (IDispatch* pDoc);

Yes, I suspect so.  But beware that holding a reference to ActiveDocument introduces a possible reference cycle (i.e. A refs B and B refs A) that would prevent your container application from shutting down.


HTH
Addam
« Last Edit: July 12, 2011, 01:37:52 PM by XMetaLOldTimer » Logged

Addam Smith, XMetaL Project Lead & Architect
JustSystems Canada Inc.
Pages: 1
Print
Jump to:  

email us