ATL8 atlsoap.h中的问题 ATL Server开发

8 篇文章 0 订阅
ATL8 atlsoap.h 中的问题
2007-3-19
ATL Server 开发
遗憾的是,这个方法也不能返回任意定制的SOAP消息,请参考我的下一篇文章:
ATLServer WebService 如何返回任意内容的 SOAP 消息给客户 --- 改写atlsoap.h
1 问题的提出
 
当我在 ATL8.0 中创建 Web Service ,当客户调用其中的 Web 方法(如: HelloWorld )返回 E_FAIL (非 S_OK )等错误 HRESULT 值时,我的 Web 服务程序遇到了问题: w3wp.exe 弹出错误对话框。我猜测应该是 msvcr80d.dll 出了问题,既使是 release 编译后运行,此问题仍不能消除。而同样的状况在 ATL7.1 时就没有发生。我使用 AJAX 客户程序( client.htm )来调用 Web 服务方法。请参考我的另一篇文章《 一个调用ATL Server WebServices AJAX客户端 》:
 
我的 Web 服务示例方法如下:
// 这是一个示例 Web 服务方法,它显示如何使用
// soap_method 属性将方法公开为 Web 方法
// 1 个版本的 HelloWorld:
// ATL8: 引发异常, w3wp.exe 弹出错误对话框
// ATL7: 无异常,但是返回消息格式不完整
     [ soap_method ]
     HRESULT HelloWorld(/*[in]*/ BSTR bstrInput, /*[out, retval]*/ BSTR *bstrOutput)
     {
         CComBSTR bstrOut(L"Hello ");
         bstrOut += bstrInput;
         *bstrOutput = bstrOut.Detach();
        
         // 下面注释掉的内容,取消注释后,可以解决本文的问题,但这不是一个好的解决方法
         // SoapFault(SOAP_E_CLIENT, L" Unspecified error ", sizeof(L"Unspecified error ")-1);
         return E_FAIL;
    }
 
当调试跟踪 WebService F5 )运行,弹出错误消息如下:
 
( 看不到图片 , 我就把文本写上拉 )
______________________________________________________
 Microsoft Visual Studio
------------------------------------------------------------------------------
 Microsoft Visual Studio C 运行时库在 w3wp.exe 中检测到一个错误。
  中断 以调试程序,或按继续以终止程序。                                        
______________________________________________________
 
当不调试运行,无论 Debug Release 版本,均产生下面的出错消息:
 
( 看不到图片 , 我就把文本写上拉 )
________________________________________________________________
 w3wp.exe - 应用程序错误                                 
---------------------------------------------------------------------------------------------
应用程序发生异常 unknown software exception (0xc000000d), 位置为 0x01cda510
要终止程序,请单击 确定
要调试程序,请单击 取消
________________________________________________________________
 
我跟踪进去,发现异常发生在 atlsoap.h 文件的下面部分(注释是我加的):
 
// 2875: 下面的 strFault.Format 会引发异常 ( m_strDetail 为中文的时候 ). 2007-03-19 张亮
     const LPCSTR s_szErrorFormat =
                   "<SOAP:Envelope xmlns:SOAP=/"" SOAPENV_NAMESPACEA "/">"
                   "<SOAP:Body>"
                   "<SOAP:Fault>"
                   "<faultcode>SOAP:%ws</faultcode>"
                   "<faultstring>%ws</faultstring>"
                   "%s%ws%s"
                   "<detail>%ws</detail>"
                   "</SOAP:Fault>"
                   "</SOAP:Body>"
                   "</SOAP:Envelope>";
        
     CStringA strFault;
     strFault.Format(s_szErrorFormat, wszFaultCode, m_strFaultString,
         m_strFaultActor.GetLength() ? "<faultactor>" : "", m_strFaultActor,
         m_strFaultActor.GetLength() ? "</faultactor>" : "",
         m_strDetail);         // m_strDetail 为中文内容的时候,发生上述错误
     // 2893
     hr = pWriteStream->WriteStream(strFault, strFault.GetLength(), NULL); // 2894
 
2 解决的办法
 
我尝试改变上面的代码,包括全部字符串转换为 ANSI ,结果都不行。(在 ATL7.1 中,即使 m_strDetail 内容为中文,如 =“ 未指定的错误 strFault.Format 方法也不会引发异常,但是返回的 SOAP 消息中, “<detail></detail>“ 为空,这说明, 8.0 C 运行库和 7.1 C 运行库的确对待问题的处理方式不同。)
 
2.1 第一种策略
 
解决的办法是改变 Web 方法 (HelloWorld) 实现,如下:
     // 2 个版本的 HelloWorld ATL8 ATL7 都正确
HRESULT HelloWorld(/*[in]*/ BSTR bstrInput, /*[out, retval]*/ BSTR *bstrOutput)
     {
          CComBSTR bstrOut(L"Hello ");
          bstrOut += bstrInput;
          *bstrOutput = bstrOut.Detach();
        
          // 下面注释掉的内容,取消注释后,可以解决本文的问题,但这不是一个好的解决方法
          SoapFault(SOAP_E_CLIENT, L" Unspecified error ", sizeof(L"Unspecified error ")-1);
          return E_FAIL;
}
 
但是,这个办法是很容易犯错误的:我们必须设置 SoapFault ... ),并且当我们设置了中文的消息:
SoapFault(SOAP_E_CLIENT, L" 未指定的错误 ", sizeof(L" 未指定的错误 ")-1);
时,错误又出现了。我觉得这是微软的一个 BUG ,希望 MS 能从根本解决这个问题。
 
 
2.2 第二种策略
 
接下来,我把我的解决办法说明如下:
1 )绝对不能在 SoapFault 中设置中文的错误消息。 使用英语吧!
2 )必须修改 atlsoap.h 的默认实现。 atlsoap.h 中找到方法 GenerateAppError ,仅需要修改 ::FormatMessageW 的第 4 参数(原来是 0 ),改为:
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH)
其他部分不要改。如下面注释部分:
virtual ATL_NOINLINE HRESULT GenerateAppError(IWriteStream *pStream, HRESULT hr)
     {
         if (pStream == NULL)
         {
              return E_INVALIDARG;
         }
 
         LPWSTR pwszMessage = NULL;
         DWORD dwLen = ::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH) , // 原来是 : 0
(LPWSTR) &pwszMessage,
0,
NULL);
         if (dwLen == 0)
         {
              pwszMessage = L"Application Error";
         }
 
         hr = SoapFault(SOAP_E_SERVER, pwszMessage, dwLen ? dwLen : -1);
         if (dwLen != 0)
         {
              ::LocalFree(pwszMessage);
         }
 
         return hr;
     }
 
3 可以喘口气么
 
一切搞定,最后,客户端 alert 出来的 HelloWorld 方法调用返回的 SOAP 消息如下:
< SOAP:Envelope
xmlns:SOAP =" http://schemas.xmlsoap.org/soap/envelope/ ">
< SOAP:Body >
< SOAP:Fault >
< faultcode > SOAP:Server </ faultcode >
< faultstring > SOAP Server Application Faulted </ faultstring >
             <detail>Unspecified error</detail>
</ SOAP:Fault >
</ SOAP:Body >
</ SOAP:Envelope >
 
 
4 后记
 
解决这个问题,花费我 2007 3 18 22:00 2007 3 19 4:30 ,近 7 个小时的时间,而且我还是希望能支持中文,但这个问题我是解决不了拉,希望高手赐教。另外还花了 2 个小时写了这篇文章。看来 atlsoap.h 中的 BUG 还不少哩。请参考下面网页(真的很值得一看),以了解更多关于 ATL SOAP 的知识:
 
如果这篇文章对您有帮助,或您有更好的解决方法,请发邮件告诉我:
 
cheungmine 2007-3-19 上海
 
 
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

车斗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值