General XMetaL Discussion

XMetaL Community Forum General XMetaL Discussion Interacting with running XMAX

  • elias

    Interacting with running XMAX

    Participants 4
    Replies 5
    Last Activity 11 years, 1 month ago

    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[/code] I've looked up this guid in the OLE/COM Object Viewer (it's a standard tool within Microsoft Visual Studio).

    Reply

    XMetaLOldTimer

    Reply to: Interacting with running XMAX

    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.

    Reply

    elias

    Reply to: Interacting with running XMAX

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

    _
        Public Shared Function RegisterActiveObject( ByVal punk As Object, ByRef rclsid As Guid, ByVal dwFlags As Integer, ByRef pdwRegister As Integer) As Integer
        End Function
        _
        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

        _
            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
    [/code]
    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.

    Reply

    elias

    Reply to: Interacting with running XMAX

    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. 

    Reply

    XMetaLOldTimer

    Reply to: Interacting with running XMAX

    [code]    
    xmaxROTid = Register_OLE32(“XMetaL.Control”, Me.AxXMetaLControl)  // BAD ASSUMPTION IS HERE    
    [/code]

    “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.

    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.

    Reply

    XMetaLOldTimer

    Reply to: Interacting with running XMAX

    …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

    Reply

  • You must be logged in to reply to this topic.

Lost Your Password?

Products
Downloads
Support