Determining Whether an Object Is Invoked As COM or As SOAP


In general, when you write an object that supports both SOAP and COM, it s preferable to avoid having to write code for special-case situations for a particular invocation method. However, there are situations when this may be necessary, and it s necessary to determine how the object was invoked.

As we mentioned in the previous section, ATL Server defaults to assuming COM invocation and only switches to using the ATL Server ISAPI-provided perthread allocator when invoked through SOAP. You can use the same method to provide a convenient way to retrieve the information about the object s invocation method. Listing 19-7 shows how to encapsulate this functionality in a base class.

Listing 19.7: Determining the Method of Invocation
start example
 // WhichInvoke.h : Declaration of the CWhichInvoke  #pragma once  #include "resource.h"       // main symbols  #include <atlsoap.h>  [ emitidl(true) ];  // IWhichInvoke  [      object,      uuid("D15E83BF-35BB-496F-9BE9-E0260443A292"),      dual,    helpstring("IWhichInvoke Interface"),      pointer_default(unique)  ]  __interface IWhichInvoke : IDispatch  {      [id(1)] HRESULT Test([out, retval] BSTR *InvokeType);  };  // CWhichInvoke  [      coclass,      threading("apartment"),      vi_progid("COM_OR_SOAP.WhichInvoke"),      progid("COM_OR_SOAP.WhichInvoke.1"),      version(1.0),      uuid("8777423D-7594-4116-94B9-70CCEE66DE27"),      helpstring("WhichInvoke Class"),      request_handler(name="Default", sdl="GenWSDL"),      soap_handler(name="WhichInvoke")  ]  class ATL_NO_VTABLE CWhichInvoke :      public IWhichInvoke  {  private:      BOOL m_fCOMInvoke;  public:      CWhichInvoke()      {          // default to COM          m_fCOMInvoke = TRUE;      }      // override InitializeHandler      HTTP_CODE InitializeHandler(          AtlServerRequest *pRequestInfo,          IServiceProvider *pProvider)      {          HTTP_CODE hcErr = __super::InitializeHandler(pRequestInfo, pProvider);          if (hcErr == HTTP_SUCCESS)          {              m_fCOMInvoke = FALSE;          }          return hcErr;      }      DECLARE_PROTECT_FINAL_CONSTRUCT()      HRESULT FinalConstruct()      {          return S_OK;      }      void FinalRelease()      {      }      [ soap_method ]      HRESULT Test(BSTR *InvokeType)      {          if (m_fCOMInvoke)              *InvokeType = SysAllocString(L"COM!");          else              *InvokeType = SysAllocString(L"SOAP!");          return S_OK;      }  public:  }; 
end example
 

In Listings 19-8 and 19-9, the boolean variable m_fCOMInvoke defaults to TRUE . The ATL Server InitializeHandler method is overridden to set m_fCOMInvoke to FALSE , as the InitializeHandler method will only be called if the object is being invoked through SOAP. The member function IsCOMInvoke accesses the m_fCOMInvoke member.

Listing 19.8: Demonstration of Determining the Method of Invocation in COM
start example
 // test.js  var obj = WScript.CreateObject("COM_OR_SOAP.WhichInvoke");  var strInvoke = obj.Test();  WScript.Echo(strInvoke); 
end example
 
Listing 19.9: Demonstration of Determining the Method of Invocation in SOAP
start example
 // test.cpp  #define _WIN32_WINNT 0x0500  #include "WhichInvoke.h"  int main()  {      CoInitialize(NULL);      {          WhichInvoke::CWhichInvoke obj;          CComBSTR bstrInvoke;          HRESULT hr = obj.Test(&bstrInvoke);          if (SUCCEEDED(hr))              printf("%ws\n", bstrInvoke);      }      CoUninitialize();  } 
end example
 

Running test.js will output COM! and running test.cpp will output SOAP!

SOAP Faults and IErrorInfo

Earlier you learned how to return custom SOAP faults from ATL Server Web services. COM has its own error-reporting mechanisms, however, and it isn t possible to directly return SOAP faults through COM. In this section you ll examine how to combine custom SOAP fault generation with COM s IErrorInfo error reporting mechanism.

You can accomplish combining SOAP faults and COM errors by adding ISupportErrorInfo to your COM object using the support_error_info attribute. You can then call AtlReportError when generating errors to provide custom error text. To generate SOAP faults based on this custom error text, you override the GenerateAppError method for CSoapHandler , which then uses the IErrorInfo object to retrieve the custom error information and inserts it into the SOAP fault. Listing 19-10 shows how to return a custom COM error using IErrorInfo.

Listing 19.10: Returning a Custom Error Using IErrorInfo
start example
 // ErrorExample.h : Declaration of the CErrorExample  #pragma once  #include "resource.h"       // main symbols  #include <atlsoap.h>  [ emitidl(true) ];  // IErrorExample  [      object,      uuid("CB3722F0-D016-409C-81F8-804520B9AB1D"),      dual,    helpstring("IErrorExample Interface"),      pointer_default(unique)  ]  __interface IErrorExample : IDispatch  {      [id(1)] HRESULT ReturnError();  };  // CErrorExample  [      coclass,      threading("apartment"),      vi_progid("ErrorFault.ErrorExample"),      progid("ErrorFault.ErrorExample.1"),      version(1.0),      uuid("C1457735-C0FD-4858-9A2D-42B60A4A93DE"),      helpstring("ErrorExample Class"),      support_error_info("IErrorExample"),      request_handler(name="Default", sdl="GenWSDL"),      soap_handler(name="ErrorExample")  ]  class ATL_NO_VTABLE CErrorExample :      public IErrorExample  {  public:      CErrorExample()      {      }      DECLARE_PROTECT_FINAL_CONSTRUCT()      HRESULT FinalConstruct()      {          return S_OK;      }      void FinalRelease()      {      }      void GenerateError(HRESULT hr, LPCWSTR wszErr)      {          AtlReportError(GUID_NULL, wszErr);      }      // override GenerateAppError      HRESULT      GenerateAppError(          IWriteStream *pStream,          HRESULT hr          )      {          CComPtr<IErrorInfo> spErr;          HRESULT hrInternal = GetErrorInfo(0, &spErr);          if (SUCCEEDED(hrInternal))          {              CComBSTR bstrErr;              hrInternal = spErr->GetDescription(&bstrErr);              if (SUCCEEDED(hrInternal) && bstrErr.m_str)              {                  return SoapFault(SOAP_E_SERVER, bstrErr, bstrErr.Length());              }          }          return SoapFault(              SOAP_E_SERVER,              L"Unexpected Error",              sizeof("Unexpected Error")-1);      }      [ soap_method ]      HRESULT ReturnError()      {          GenerateError(0x80040200, L"Custom Failure Text");          return 0x80040200;      }  public:  }; 
end example
 

Listing 19-11 shows an example of how to retrieve the information from a SOAP client.

Listing 19.11: Retrieving Custom Error Information from IErrorInfo
start example
 // test.cpp  #define _WIN32_WINNT 0x0500  #include "ErrorExample.h"  int main()  {      CoInitialize(NULL);      {          ErrorExample::CErrorExample obj;          HRESULT hr = obj.ReturnError();          if (FAILED(hr))              printf("%ws\n", obj.m_fault.m_strDetail);      }      CoUninitialize();  } 
end example
 

When called, the program will output Custom Failure Text.




ATL Server. High Performance C++ on. NET
Observing the User Experience: A Practitioners Guide to User Research
ISBN: B006Z372QQ
EAN: 2147483647
Year: 2002
Pages: 181

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net