How to Edit COM Library to Provide Method Access

1

In our header file we have the class definition where GroupInit, EditInit were protected. I want to be able to access these methods by adding a reference to the generated GrpSvr.tlb file from a C# solution so I changed these to public...

#if !defined(AFX_GRPCALL_H__FFB54BC3_B15E_11D1_99BC_0000E803C444__INCLUDED_)
#define AFX_GRPCALL_H__FFB54BC3_B15E_11D1_99BC_0000E803C444__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif
class CGrpCall : public CCmdTarget
{
    DECLARE_DYNCREATE(CGrpCall)
    CGrpCall(); // protected constructor used by dynamic creation
// Attributes
public:
// Operations
public:
    public:
    virtual void OnFinalRelease();
    DECLARE_MESSAGE_MAP()
    DECLARE_OLECREATE(CGrpCall)
    afx_msg BSTR GroupInit(LPCTSTR bstrIniFile, BOOL bDiagErr, BOOL bProcErr);
    afx_msg BSTR EditInit(LPCTSTR bstrIniFile);
    DECLARE_DISPATCH_MAP()
    DECLARE_INTERFACE_MAP()
   // Implementation
protected:
   virtual ~CGrpCall();
};
#endif // !defined(AFX_GRPCALL_H__FFB54BC3_B15E_11D1_99BC_0000E803C444__INCLUDED_)

The GrpSvr.cpp code is

IMPLEMENT_DYNCREATE(CGrpCall, CCmdTarget)
CGrpCall::CGrpCall() {
    EnableAutomation();
    AfxOleLockApp();
    Initialize(FALSE);
}

CGrpCall::~CGrpCall() {
    AfxOleUnlockApp();
    GroupTerm();
}

void CGrpCall::OnFinalRelease() {
    CCmdTarget::OnFinalRelease();
}

BEGIN_MESSAGE_MAP(CGrpCall, CCmdTarget)
END_MESSAGE_MAP()

BEGIN_DISPATCH_MAP(CGrpCall, CCmdTarget)
    DISP_FUNCTION(CGrpCall, "GroupInit", GroupInit, VT_BSTR, VTS_BSTR VTS_BOOL VTS_BOOL)
    DISP_FUNCTION(CGrpCall, "EditInit", EditInit, VT_BSTR, VTS_BSTR)
END_DISPATCH_MAP()

static const IID IID_IGrpCall =
{ 0xffb54bc2, 0xb15e, 0x11d1, { 0x99, 0xbc, 0x0, 0x0, 0xe8, 0x3, 0xc4, 0x44 } };

BEGIN_INTERFACE_MAP(CGrpCall, CCmdTarget)
    INTERFACE_PART(CGrpCall, IID_IGrpCall, Dispatch)
END_INTERFACE_MAP()

IMPLEMENT_OLECREATE(CGrpCall, "GrpSvr.GrpCall", 0xffb54bc2, 0xb15e, 0x11d1, 
   0x99, 0xbc, 0x0, 0x0, 0xe8, 0x3, 0xc4, 0x44)

BSTR CGrpCall::GroupInit(LPCTSTR bstrIniFile, BOOL bDiagErr, BOOL bProcErr) { /* Some Code */ }
BSTR CGrpCall::EditInit(LPCTSTR bstrIniFile) { /* Some Code */ }

I can now see these methods by adding a reference in C# and doing

GrpSvr.GrpCall g = new GrpSvr.GrpCall();
g.GroupInit(this.strCommandFilePath, true, true);

However, this is giving

An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll. ... Class not registered ...

What do I have to do to this code in order to be able to call the methods directly?

Thanks for your time.


Edit. following the comments I opened up the .tlb file in OLEView and I get the following output

// Generated .IDL file (by the OLE/COM Object Viewer)
// 
// typelib filename: GrpSvr.tlb

[
  uuid(FFB54BB5-B15E-11D1-99BC-0000E803C444),
  version(1.0),
  custom(DE77BA64-517C-11D1-A2DA-0000F8773CE9, 134218331),
  custom(DE77BA63-517C-11D1-A2DA-0000F8773CE9, 1396349854),
  custom(DE77BA65-517C-11D1-A2DA-0000F8773CE9, "Created by MIDL version 8.00.0603 at Tue Apr 01 11:57:34 2014
")

]
library GrpSvr
{
    // TLib :     // TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
    importlib("stdole2.tlb");

    // Forward declare all types defined in this typelib
    dispinterface IGrpCall;

    [
      uuid(FFB54BC2-B15E-11D1-99BC-0000E803C444)
    ]
    dispinterface IGrpCall {
        properties:
        methods:
            [id(0x00000001)]
            BSTR GroupInit(
                            BSTR bstrIniFile, 
                            VARIANT_BOOL bDiagErr, 
                            VARIANT_BOOL bProcErr);
            [id(0x00000002)]
            BSTR EditInit(BSTR bstrIniFile);
            [id(0x00000003)]
            BSTR GroupTerm();
            [id(0x00000004)]
            BSTR GetVars(
                            short* sNumInp, 
                            short* sLastOP, 
                            short* sLenDiag, 
                            short* sLenProc, 
                            short* sNumDiag, 
                            short* sNumProc, 
                            BSTR* bstrInpFile, 
                            BSTR* bstrOutFile, 
                            BSTR* bstrDbFile);
            [id(0x00000005)]
            BSTR GetFldDets(
                            short sIndex, 
                            BSTR* bstrFldName, 
                            short* sNumFld, 
                            short* sFldNum, 
                            short* sFldLen, 
                            short* sFldType, 
                            short* sFldPos);
            [id(0x00000006)]
            long SetVersionDate(BSTR bstrDate);
            [id(0x00000007)]
            BSTR GetLabel(
                            short sFldNum, 
                            BSTR bstrCode);
            [id(0x00000008)]
            BSTR BatchProcess(long* lNRecs);
            [id(0x00000009)]
            BSTR FldEdit(
                            short sFld, 
                            BSTR bstrVal);
            [id(0x0000000a)]
            BSTR GroupRecord(BSTR bstrRec);
            [id(0x0000000b)]
            BSTR GetReport();
            [id(0x0000000c)]
            BSTR GetFldVal(
                            short sFld, 
                            long sOcc, 
                            BSTR* bstrVal);
            [id(0x0000000d)]
            BSTR EditRec(BSTR bstrRec);
            [id(0x0000000e)]
            BSTR MakeRec(
                            short sFld, 
                            short sOcc, 
                            BSTR bstrVal);
            [id(0x0000000f)]
            BSTR GetRecord();
            [id(0x00000010)]
            BSTR GetCount(long* lRecs);
            [id(0x00000011)]
            BSTR WriteReport();
            [id(0x00000012)]
            BSTR Test(VARIANT_BOOL bTest);
            [id(0x00000013)]
            BSTR GetFldVal2(
                            short sFld, 
                            short sOcc);
    };

    [
      uuid(FFB54BC4-B15E-11D1-99BC-0000E803C444)
    ]
    coclass GrpCall {
        [default] dispinterface IGrpCall;
    };
};
c++
com
interop
asked on Stack Overflow Apr 3, 2014 by MoonKnight • edited Apr 7, 2014 by MoonKnight

1 Answer

1

As this is an MFC project, a DECLARE_OLETYPELIB/IMPLEMENT_OLETYPELIB has to be present in the class declaration/implementation. Some other additional steps are required to register the type library properly:

TN065: Dual-Interface Support for OLE Automation Servers

I suggest using OleView tool for troubleshooting. Find your "GrpSvr.GrpCall" object in the tree, right click it and try to create from there. Check if the corresponding registry keys are pointing to the correct .DLL (and .TLB, if registered separate).

answered on Stack Overflow Apr 7, 2014 by noseratio

User contributions licensed under CC BY-SA 3.0