> OK, it was my fault.
>
> First, the IID I should have been using for
> CoCreateInstance() is "Document", not "IFoo". This makes a little
> sense if you think of the clsid, L"IFoo.Document"... I can't put the
> reason into words exactly, but there you go.

One serious recommendation: stay away from MFC when writing COM servers, and
use ATL instead.  It's easier to use, easier to read, has less bloat, has
less unintuitive conventions, and IMO rocks!

And there is also very good support for it on the web.  There's even a
dedicated mailing list: [EMAIL PROTECTED]

> I actually wondered about this and had tried it; the call to get the
> 'interface' (it did get retrieved as if it were an interface, but I'm
> a little confused about why it's not IDocument... so I'll keep quiet
> before I munge this any
> further!) /succeeded/, as opposed to trying to retrieve IFoo which
> failed with E_NOINTERFACE.
>
> The problem was, when I tried to use that smart pointer to call the
> method, the code access-violated... and I was led up the wrong path
> thinking that it was something wrong about the smart pointer I had
> created, and so Document couldn't be right.
>
> Well, it wasn't; the problem was that I was calling CoInitialize() and
> CoUninitialize() within the routine which created the smart pointer
> and used it. Trouble is, that meant that
> CoUninitialize() was being called before the end of the routine, and
> thus before the smart pointer had gone out of scope and tried to call
> Release()... so all hell broke loose.

That's a common gotcha.  I usually do something like:

 class COMInit
 {
  COMInit() { CoInitialize( NULL ); }
  ~COMInit() { CoUninitialize(); }
 } const g_init;

> The only reason I found out was because the book "Inside Visual C++"
> led me back to focus on Document, and then it finally clicked what I'd
> done wrong.
>
>
>
> Now, just so you don't get away without listening to more COM crap
> {;v)...
>
> There was one final gotcha - nothing tragic this time, just an
> irritation.
> The method I had defined tried to return a long integer to the calling
> code - something non-zero to indicate success, or zero for failure.

In COM, the HRESULT 0 is S_OK, which means success with no further question.
And every HRESULT code with the highest bit not set is also a success code
(S_xxx) even if it's not defined in any header.  And all HRESULT codes with
the highest bit set are error codes (E_xxx).

In Automation, there's a type called VARIANT_BOOL which maps to the Boolean
type in VB and scripting languages.  It's a typedef for short, and there are
two constants: VARIANT_TRUE (-1) and VARIANT_FALSE (0) defined.

When you want to return a Boolean, you should be using VARIANT_BOOL, like I
will show below.

> The VB client handled it just fine, but for some strange reason the VC
> client kept getting back zero - even though the server itself
> confirmed that it was sending back non-zero.

That zero meant S_OK.  In fact, you should've said: for some strange reason,
VB handles it just fine!

> I traced it a little and found that the inline method defined by the
> .tli file generated by the #import returns zero from the
> _com_dispatch_method() call it makes. Now, this is no big deal since
> it's easy to fix: simply add another out parameter to the method and
> forget the return value. I also seem to remember reading somewhere
> that you should never return anything from a COM call except an
> HRESULT anyway - perhaps this is the reason? Anyway, I'm a happy bunny
> now (until tomorrow, no doubt), so I'll leave you all to enjoy your
> Sunday {:v)

Yes, what you read is true.  A method that returns a boolean should be like
this:


  // IDL
  [id(nnn)] HRESULT MyMethod([out, retval] VARIANT_BOOL * pVal);

  // C++ declaration
  STDMETHOD(MyMethod)(VARIANT_BOOL * pVal);

  // C++ definition
  STDMETHODIMP CMyClass::MyMethod(VARIANT_BOOL * pVal)
  {
   if (!pVal)
    return E_INVALIDARG;
   else
   {
    *pVal = VARIANT_TRUE;
    return S_OK;
   }
  }

  // VB client
  Dim MyObj As New MyClass
  Dim b As Boolean
  b = MyObj.MyMethod()

  // C++ client
  CComPtr< IMyClass > spObj;
  spObj.CoCreateInstance( CLSID_MyClass );
  VARIANT_BOOL b;
  spObj->MyMethod( &b );

HTH,
-------------
Ehsan Akhgari

Farda Technology (www.farda-tech.com)

List Owner: [EMAIL PROTECTED]

[ Email: [EMAIL PROTECTED] ]
[ WWW: http://www.beginthread.com/Ehsan ]

Whoever fights monsters should see to it that in the process he does not
become a monster. And when you look long into the abyss, the abyss also
looks into you.
-Beyond Good And Evil, F. W. Nietzsche





Reply via email to