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客户端
》:
http://blog.csdn.net/cheungmine/archive/2006/09/07/1190164.aspx
我的
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
的知识:
http://www.rsdn.ru/article/xml/soapatl.xml
如果这篇文章对您有帮助,或您有更好的解决方法,请发邮件告诉我:
cheungmine
于
2007-3-19
上海