How to create and pass a COM IDispatch pointer as callback from a C++ Console Client to a C++ WinService successfully? -


in advance sorry long post, given there many parts involved, , not sure can making mistake, hence, need post parts involved. please not assume anything, can making type of error here.

problem:

1) real problem: learning com.

2) need pass idispatch pointer console client (consoleclient) in c++ parameter com function in windows service (winservice). idispatch pointer acts callback. winservice knows name of function called. attempts have been unsuccessulf. getting different errors like: no implemented, rpc unavailable, etc..

note: following error correct! edited after @igor pointed out error: have do-while (which removed main()) in sta thread. added message pump (getmessage, translatemessage , dispatchmessage) in main() thread (instead of do-while) , problem fixed!

i have winservice exposing following com interface (winservice's idl file):

[ object, uuid(dbe8bc31-9d2b-4f4b-903a-b40473408de9), dual, nonextensible, pointer_default(unique) ] interface iwinservice : idispatch { ///here there more functions..     [id(4), helpstring("interface help")]      hresult winservicecomfunction( [in] variant vcallback, [out, retval] long* preturn );     //here there more functions...  };    [     uuid(def3bfae-adf4-493b-8d01-e47a279225c5),     version(1.0),     helpstring("lib help") ] library winservicelib {     importlib("stdole2.tlb");  [            uuid(ac290dc9-8cb4-4502-a73c-2bdaec4b215a)       ] coclass cowinservice     {         [default] interface iwinservice;     }; } 

the winservice internally expects vcallback.vt = vt_dispatch, i.e., callback pointer need pass in when invoke winservicecomfunction consoleclient.exe app. winservice knows name of function acts callback. i.e., winservice calls idispatch-pointer-callback getidsofname "functioncallback" parameter. however, here getting different errors in winservice like: no implemented, rpc unavailable, etc.. no callback executed (the consoleclient not receive back).

what have done far (all following source code found in consoleclient.exe) consoleclient.exe main.cpp:

int _tmain(int argc, _tchar* argv[]) {     coinitialize(null);      //to brief: let's think have idispatch pointer winservice interface iwinservice:     ccomptr<idispatch> piwinservice; //piwinservice     //here queried iwinservice interface...it successful!!!      olechar * winservicenamefunction = l"winservicecomfunction";      dispid dispid;     hr = piwinservice->getidsofnames( iid_null, &winservicenamefunction, 1, locale_user_default, &dispid );      if ( failed( hr ) )     {         wprintf( l"getidsofnames failed" );         return 1;     }     else     {         wprintf( l"getidsofnames succeeded!" );     }      ccomptr<idispatch> consoleclientcallback( new cconsoleclientinterface() );     cconsoleclientinterface *sanity = dynamic_cast<cconsoleclientinterface *>( consoleclientcallback.p );      if ( nullptr == pautocallback )     {         wprintf( l"cconsoleclientinterface pointer failed\n" );         return 1;     }     else     {         wprintf( l"cconsoleclientinterface pointer succeeded\n" );     }      dword dwregister;     hr = coregisterclassobject(clsid_coconsoleclient, consoleclientcallback.p,          clsctx_local_server, regcls_multipleuse, &dwregister);      if(failed(hr))     {         wprintf(l"coregisterclassobject failed\n");         return 1;     }     else     {         wprintf(l"coregisterclassobject succeeded\n");     }      ccomvariant paramcallback( consoleclientcallback.detach() );     variantarg varparams[] = { paramcallback };     dispparams dispparams = { vargs, null, 1, 0 };      hr = pptr->invoke(         dispid,         iid_null,         locale_system_default,         dispatch_method,         &dispparams,         null,         null,         null);      if ( failed( hr ) )     {         wprintf( l"invoke failed" );         return 1;     }     else     {         wprintf( l"invoke succeeded" );     }      msg msg;     while(getmessage(&msg, null, 0, 0))     {         translatemessage(&msg);         dispatchmessage(&msg);     }      corevokeclassobject(dwregister);     couninitialize();     return 0; } 

all main succesfully executed. however, never callback. when winservice tries queryinterface teh idispatch pointer callback, throws erros like: no implemented, rpc unavailable, among others...

template class create consoleclient idispatch interface from: http://blogs.msdn.com/b/oldnewthing/archive/2013/06/12/10425215.aspx

disinterfacebase.h:

template<typename dispinterface> class cdispinterfacebase : public dispinterface { public: cdispinterfacebase() : m_cref(1), m_dwcookie(0) { }  /* iunknown */ ifacemethodimp queryinterface(refiid riid, void **ppv) {     *ppv = nullptr;     hresult hr = e_nointerface;     if (riid == iid_iunknown || riid == iid_idispatch ||         riid == __uuidof(dispinterface))     {         *ppv = static_cast<dispinterface *>             (static_cast<idispatch*>(this));         addref();         hr = s_ok;     }     return hr; }  ifacemethodimp_(ulong) addref() {     return interlockedincrement(&m_cref); }  ifacemethodimp_(ulong) release() {     long cref = interlockeddecrement(&m_cref);     if (cref == 0) delete this;     return cref; }  // *** idispatch *** ifacemethodimp gettypeinfocount(uint *pctinfo) {     *pctinfo = 0;     return e_notimpl; }  ifacemethodimp gettypeinfo(uint itinfo, lcid lcid,     itypeinfo **pptinfo) {     *pptinfo = nullptr;     return e_notimpl; }  ifacemethodimp getidsofnames(refiid, lpolestr *rgsznames,     uint cnames, lcid lcid,     dispid *rgdispid) {     return e_notimpl; }  ifacemethodimp invoke(     dispid dispid, refiid riid, lcid lcid, word wflags,     dispparams *pdispparams, variant *pvarresult,     excepinfo *pexcepinfo, uint *puargerr) {     if (pvarresult) variantinit(pvarresult);     return simpleinvoke(dispid, pdispparams, pvarresult); }  // derived class must implement simpleinvoke virtual hresult simpleinvoke(dispid dispid,     dispparams *pdispparams, variant *pvarresult) = 0;  public:     hresult connect(iunknown *punk)     {         hresult hr = s_ok;         ccomptr<iconnectionpointcontainer> spcpc;         if (succeeded(hr)) {             hr = punk->queryinterface(iid_ppv_args(&spcpc));         }         if (succeeded(hr)) {             hr = spcpc->findconnectionpoint(__uuidof(dispinterface), &m_spcp);         }         if (succeeded(hr)) {             hr = m_spcp->advise(this, &m_dwcookie);         }         return hr;     }  void disconnect() {     if (m_dwcookie) {         m_spcp->unadvise(m_dwcookie);         m_spcp.release();         m_dwcookie = 0;     } }  private:     long m_cref;     ccomptr<iconnectionpoint> m_spcp;     dword m_dwcookie; }; 

the actual idispatch implementation in consoleclient consoleclient.h

class cconsoleclientinterface : public cdispinterfacebase<iconsoleinterface> { public:      cconsoleclientinterface() { }     ~cconsoleclientinterface() { }  stdmethodimp getidsofnames(refiid, lpolestr *rgsznames,         uint cnames, lcid lcid,         dispid *rgdispid)     {             hresult hr = e_fail;      if(_wcsicmp(*rgsznames, l"functioncallback") == 0)     {         *rgdispid = 1;         hr= s_ok;     }     else     {         hr= disp_e_unknowninterface;     }      if(failed(hr))     {         std::cout << l"failed\n";     }      return hr; }      hresult simpleinvoke(         dispid dispid, dispparams *pdispparams, variant *pvarresult)     { //      switch (dispid)  //      { //      case 4:             std::cout << l"simpleinvoke" << std::endl; //this never printed (for error trying figure out)             hresult hr = functioncallback( pdispparams->rgvarg[1].intval, pdispparams->rgvarg[0].parray ); //          break; //      }         return hr;     }      hresult functioncallback( long longvalue, lpsafearray safearray )     {         //so simple, want value printed in consoleclient's console! unfortunately not happening!         std::cout << longvalue << std::endl;          return s_ok;     } }; 

and consoleclient.idl

[     object,     uuid(cd08b160-558a-4251-885c-173a08a461f1),     dual,     nonextensible,     helpstring("iconsoleinterface interface"),     pointer_default(unique) ] interface iconsoleinterface : idispatch{     [id(1), helpstring("method functioncallback")]      hresult functioncallback([in] long longvalue, [in] lpsafearray safearray ); }; [     uuid(f3445a9e-555b-4729-952b-8b72b8db2e37),     version(1.0),     helpstring("consoleclientlib lib") ] library consoleclientlib  {     importlib("stdole2.tlb");     [         uuid(eff9ec78-3031-4558-9ba3-5b2641ccb304),         helpstring("coconsoleclient class")     ]     coclass consoleclientinterface      {         [default] interface iconsoleinterface;     }; }; 

i have created:

hkey_classes_root\clsid\{eff9ec78-3031-4558-9ba3-5b2641ccb304} //clsid (default) reg_sz = c:\program files\common files\consoleclient.exe hkey_classes_root\clsid\{eff9ec78-3031-4558-9ba3-5b2641ccb304}\localserver32 threadingmodel reg_sz = both 

also have registered tlb using regtlibv12.exe

sorry long post, com forces me this, in particular new com , not know can making mistake.

note: sure invoke (from consoleclient.exe) winservice com function (winservicecomfunction) successful (i debugged , hits inside function after invoke).

note2: sure winservice using callback works. there other implementations (in different programming languages) making use of mechanism via same function (winservicecomfunction) in winservice.

any help? in advance!