How to use ISAXXMLReader in ATL Server Web Service Project

F

FS Liu

Hi,

In my current ATL server project, I have to parse the
input in the client application's request to find out
the different combination of parameters, instead of
using SOAP. For this reason, I am not using ATL server
web service project. On client side, I use POST to send
XML to web server. I know I should use ISAXXMLReader in
the server program. I also know that the parser can be
used for many different handlers in the DLL. I found some
example of SAX2 from Microsoft as standalone program.

ISAXXMLReader* pRdr = NULL;
HRESULT hr = CoCreateInstance(
__uuidof(SAXXMLReader),
NULL,
CLSCTX_ALL,
__uuidof(ISAXXMLReader),
(void **)&pRdr);
if(!FAILED(hr))
{
MyContent * pMc = new MyContent();
hr = pRdr->putContentHandler(pMc);
SAXErrorHandlerImpl * pEc =
new SAXErrorHandlerImpl();
hr = pRdr->putErrorHandler(pEc);
static wchar_t URL[1000];
mbstowcs( URL, argv[1], 999 );
wprintf(L"\nParsing document: %s\n", URL);
hr = pRdr->parseURL(URL);
printf("\nParse result code: %08x\n\n",hr);
pRdr->Release();
delete pMc;
}
This looks like a half COM program. Is this against
ATL Server project? How to make this per thread function?
What should I do to make it safe, thread-safe, no memory
leak, etc. Due to the lack of documents and books, I
cannot find more examples or information. Now, I still
have some trouble in using it in ATL server application.

Coud anyone help?

Thank you very much.

FS Liu
 
B

Bogdan Crivat [MSFT]

Hi

Mostly for SOAP purposes, ATL Server applications already provide a
per-thread ISAXXMLReader.
( You can disable this feature by defining #define ATL_NO_SOAP, but it is ON
by default)
You can access this per-thread ISAXXMLReader in your request handler with
code like below:

CComPtr<ISAXXMLReader> spReader;
HRESULT hRet =
m_spServiceProvider->QueryService(__uuidof(ISAXXMLReader),
__uuidof(ISAXXMLReader), &spReader)

Hope this helps,

--
--
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Please do not send email directly to this alias. It is for newsgroup
purposes only.

thanks,
bogdan
 
F

FS Liu

Hi, Bogdan,

Thank you so much for the example. I still have a problem
about the use of content handler class, MyContent. All the
Microsoft examples use
MyContent * pMc = new MyContent();
I defined a content handler that has member variables for
pairs of node and value. After running spReader->parse(),
I use the resultant pairs in the rest of the program. Is
it a better idea to use
CComPtr<MyContent> pMc;
in ATL Server application project for easier memory
management? To do so, is there any special requirement to
define the content handler MyContent? Here is my code:
CComHeapPtr<CHAR> m_RequestBuffer;// buffer for
client POST data.
CComPtr<ISAXXMLReader> spReader;
HRESULT hr = m_spServiceProvider->QueryService(
__uuidof(ISAXXMLReader), &spReader)
if(!FAILED(hr))
{
CComPtr<MyContent> pMc;
if (!pMc)
return S_ERROR;
hr = spReader->putContentHandler(pMc);
SAXErrorHandlerImpl * pEc =
new SAXErrorHandlerImpl();
hr = spReader->putErrorHandler(pEc);
static wchar_t URL[1000];
mbstowcs( URL, argv[1], 999 );
VARIANT MyVariant;
MyVariant.vt = VT_BSTR;
MyVariant.bstrVal =
(BSTR)m_RequestBuffer;// ERROR HERE!
hr = spReader->parse(MyVariant);
spReader->Release();//Do we need this here?
ATLTRACE("Node: %s Value:%d\n",pMc->Name,
pMc->Value);
}
On the other hand, given m_RequestBuffer as a dynamically
allocated memory according to the data length of client
POST, I have trouble in packing m_RequestBuffer into a
VARIANT to pass to parse(), because the compiler cannot
convert m_RequestBuffer from CHAR to BSTR (Please read the
comment in the program.) Is there an efficient way (e.g.
data type or class) to get client POST data and pass it to
spReader->parse() directly, without converting from WCS to
MBS or vice versa. Finally, do I have to do clean up
with "spReader->Release();" for the per-thread spReader?

Thank you very much.

-----Original Message-----
Hi

Mostly for SOAP purposes, ATL Server applications already provide a
per-thread ISAXXMLReader.
( You can disable this feature by defining #define ATL_NO_SOAP, but it is ON
by default)
You can access this per-thread ISAXXMLReader in your request handler with
code like below:

CComPtr<ISAXXMLReader> spReader;
HRESULT hRet =
m_spServiceProvider->QueryService(__uuidof(ISAXXMLReader),
__uuidof(ISAXXMLReader), &spReader)

Hope this helps,

--
--
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Please do not send email directly to this alias. It is for newsgroup
purposes only.

thanks,
bogdan




FS Liu said:
Hi,

In my current ATL server project, I have to parse the
input in the client application's request to find out
the different combination of parameters, instead of
using SOAP. For this reason, I am not using ATL server
web service project. On client side, I use POST to send
XML to web server. I know I should use ISAXXMLReader in
the server program. I also know that the parser can be
used for many different handlers in the DLL. I found some
example of SAX2 from Microsoft as standalone program.

ISAXXMLReader* pRdr = NULL;
HRESULT hr = CoCreateInstance(
__uuidof(SAXXMLReader),
NULL,
CLSCTX_ALL,
__uuidof(ISAXXMLReader),
(void **)&pRdr);
if(!FAILED(hr))
{
MyContent * pMc = new MyContent();
hr = pRdr->putContentHandler(pMc);
SAXErrorHandlerImpl * pEc =
new SAXErrorHandlerImpl();
hr = pRdr->putErrorHandler(pEc);
static wchar_t URL[1000];
mbstowcs( URL, argv[1], 999 );
wprintf(L"\nParsing document: %s\n", URL);
hr = pRdr->parseURL(URL);
printf("\nParse result code: %08x\n\n",hr);
pRdr->Release();
delete pMc;
}
This looks like a half COM program. Is this against
ATL Server project? How to make this per thread function?
What should I do to make it safe, thread-safe, no memory
leak, etc. Due to the lack of documents and books, I
cannot find more examples or information. Now, I still
have some trouble in using it in ATL server application.

Coud anyone help?

Thank you very much.

FS Liu


.
 
B

Bogdan Crivat [MSFT]

Please see inlines (look for [Bogdan Crivat])
Hope this helps, let me know if you run into any other issues

--
--
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Please do not send email directly to this alias. It is for newsgroup
purposes only.

thanks,
bogdan




FS Liu said:
Hi, Bogdan,

Thank you so much for the example. I still have a problem
about the use of content handler class, MyContent. All the
Microsoft examples use
MyContent * pMc = new MyContent();
I defined a content handler that has member variables for
pairs of node and value. After running spReader->parse(),
I use the resultant pairs in the rest of the program. Is
it a better idea to use
CComPtr<MyContent> pMc;
in ATL Server application project for easier memory
management? To do so, is there any special requirement to
define the content handler MyContent? Here is my code:

[Bogdan Crivat] -- Yes, this should be a smart pointer. The SAX Reader will
AddRef and Release the handler repeatedly. CComPtr is the right way of
ensuring the
life span of the handler object

CComHeapPtr<CHAR> m_RequestBuffer;// buffer for
client POST data.
CComPtr<ISAXXMLReader> spReader;
HRESULT hr = m_spServiceProvider->QueryService(
__uuidof(ISAXXMLReader), &spReader)
if(!FAILED(hr))
{
CComPtr<MyContent> pMc;


[Bogdan Crivat] -- Based on my understanding of your code, I guess a
CreateInstance should appear here. I might be wrong, though
Also, below, you might want to have your own implementation of
ISAXErrorHandler (which can be included in your SAX Handler class)
This would allow you to collect the error and decide later what to do (how
to send the information back to the client).
I might be wrong, as I am not familiar with the SAXErrorHandlerImpl


if (!pMc)
return S_ERROR;
hr = spReader->putContentHandler(pMc);
SAXErrorHandlerImpl * pEc =
new SAXErrorHandlerImpl();
hr = spReader->putErrorHandler(pEc);
static wchar_t URL[1000];
mbstowcs( URL, argv[1], 999 );
VARIANT MyVariant;
MyVariant.vt = VT_BSTR;
MyVariant.bstrVal =
(BSTR)m_RequestBuffer;// ERROR HERE!
hr = spReader->parse(MyVariant);
spReader->Release();//Do we need this here?
ATLTRACE("Node: %s Value:%d\n",pMc->Name,
pMc->Value);
}
On the other hand, given m_RequestBuffer as a dynamically
allocated memory according to the data length of client
POST, I have trouble in packing m_RequestBuffer into a
VARIANT to pass to parse(), because the compiler cannot
convert m_RequestBuffer from CHAR to BSTR (Please read the
comment in the program.) Is there an efficient way (e.g.
data type or class) to get client POST data and pass it to
spReader->parse() directly, without converting from WCS to
MBS or vice versa.

[Bogdan Crivat]
The Client POST data does not have to be copied. It is available as a stream
interface and
can be passed directly to the SAXXMLReader. See the following code snippet
for an example:

// Create a stream wrapper on top of the HTTP Server Context
CStreamOnServerContext s(m_pRequestInfo->pServerContext);
// Now create a variant that will contain the IUnknown of the IStream object
above
CComVariant varStream;
varStream = static_cast<IUnknown*>(&s);
HRESULT hr = spReader->parse(varStream);
If posible, please try to take a look at the atlsoap.h file coming with VS.
That file (the ATL Server SOAP implementation)
has to solve problems similar to the ones you have



Finally, do I have to do clean up
with "spReader->Release();" for the per-thread spReader?
[Bogdan Crivat]
No, you don't have to call an extra release. Basically, your code should
look like:
{
CComPtr<ISAXXMLReader> spReader;
m_spServiceProvider->QueryService(..., &spReader);
...
spReader->putContentHandler(...)
...
spReader->parse()
...
}
Let's assume that initially the ref count for the per-thread reader is 1.
QueryService will make it 2.
The destructor of the spReader smart pointer will call Release once and make
it back to 1, therefore ready for being used again on the same thread, with
different
data




Thank you very much.

-----Original Message-----
Hi

Mostly for SOAP purposes, ATL Server applications already provide a
per-thread ISAXXMLReader.
( You can disable this feature by defining #define ATL_NO_SOAP, but it is ON
by default)
You can access this per-thread ISAXXMLReader in your request handler with
code like below:

CComPtr<ISAXXMLReader> spReader;
HRESULT hRet =
m_spServiceProvider->QueryService(__uuidof(ISAXXMLReader),
__uuidof(ISAXXMLReader), &spReader)

Hope this helps,

--
--
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Please do not send email directly to this alias. It is for newsgroup
purposes only.

thanks,
bogdan




FS Liu said:
Hi,

In my current ATL server project, I have to parse the
input in the client application's request to find out
the different combination of parameters, instead of
using SOAP. For this reason, I am not using ATL server
web service project. On client side, I use POST to send
XML to web server. I know I should use ISAXXMLReader in
the server program. I also know that the parser can be
used for many different handlers in the DLL. I found some
example of SAX2 from Microsoft as standalone program.

ISAXXMLReader* pRdr = NULL;
HRESULT hr = CoCreateInstance(
__uuidof(SAXXMLReader),
NULL,
CLSCTX_ALL,
__uuidof(ISAXXMLReader),
(void **)&pRdr);
if(!FAILED(hr))
{
MyContent * pMc = new MyContent();
hr = pRdr->putContentHandler(pMc);
SAXErrorHandlerImpl * pEc =
new SAXErrorHandlerImpl();
hr = pRdr->putErrorHandler(pEc);
static wchar_t URL[1000];
mbstowcs( URL, argv[1], 999 );
wprintf(L"\nParsing document: %s\n", URL);
hr = pRdr->parseURL(URL);
printf("\nParse result code: %08x\n\n",hr);
pRdr->Release();
delete pMc;
}
This looks like a half COM program. Is this against
ATL Server project? How to make this per thread function?
What should I do to make it safe, thread-safe, no memory
leak, etc. Due to the lack of documents and books, I
cannot find more examples or information. Now, I still
have some trouble in using it in ATL server application.

Coud anyone help?

Thank you very much.

FS Liu


.
 
F

FS Liu

Hi, Bogdan,

Thank you very much for the valuable message. After I
declare
CComPtr <MyContent> pContent;
pContent is NULL. Yes, you are right. I should
CreateInstance after this line. So, I change my program
as (a simplified version):
CComPtr <ISAXXMLReader> spReader;
hr = m_spServiceProvider->QueryService(
__uuidof(ISAXXMLReader), &spReader);
CComPtr <MyContent> pContent;
//pContent = new MyContent();
//hr = pContent.CoCreateInstance(
// __uuidof(MyContent), NULL,
// CLSCTX_INPROC_SERVER);
hr = spReader->putContentHandler(pContent);
CStreamOnServerContext s(m_pRequestInfo-
pServerContext);
CComVariant varStream;
varStream = static_cast<IUnknown*>(&s);
ATLTRACE((char *)(varStream.bstrVal));
hr = spReader->parse (varStream);

When I use
pContent = new MyContent();
to create the instance, VS.NET compiler reports a message
saying "cannot instanciate the class" (I am using a
Japanese version. I don't know the exact wording of the
message in English). Does this mean that I have to include
some header files from VS.NET, such as msxml2.h or
something else? When I use
hr = pContent.CoCreateInstance(__uuidof
(MyContent), NULL, CLSCTX_INPROC_SERVER);
the compiler also complains: there is no associated GUID.
I read atlsoap.h and found the parseFault() function. It
is similar to the above code, except the creation of
content handler. I tried several ways to create an
instance, but failed.

I feel I just have one step further to clearify this
issue, but cannot find enough document. Could you help? By
the way, "ATLTRACE((char *)(varStream.bstrVal));" does
not print the XML string. Do you know why?

Thank you very much.

FS Liu



-----Original Message-----
Please see inlines (look for [Bogdan Crivat])
Hope this helps, let me know if you run into any other issues

--
--
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Please do not send email directly to this alias. It is for newsgroup
purposes only.

thanks,
bogdan




FS Liu said:
Hi, Bogdan,

Thank you so much for the example. I still have a problem
about the use of content handler class, MyContent. All the
Microsoft examples use
MyContent * pMc = new MyContent();
I defined a content handler that has member variables for
pairs of node and value. After running spReader->parse (),
I use the resultant pairs in the rest of the program. Is
it a better idea to use
CComPtr<MyContent> pMc;
in ATL Server application project for easier memory
management? To do so, is there any special requirement to
define the content handler MyContent? Here is my code:

[Bogdan Crivat] -- Yes, this should be a smart pointer. The SAX Reader will
AddRef and Release the handler repeatedly. CComPtr is the right way of
ensuring the
life span of the handler object

CComHeapPtr<CHAR> m_RequestBuffer;// buffer for
client POST data.
CComPtr<ISAXXMLReader> spReader;
HRESULT hr = m_spServiceProvider->QueryService(
__uuidof(ISAXXMLReader), &spReader)
if(!FAILED(hr))
{
CComPtr<MyContent> pMc;


[Bogdan Crivat] -- Based on my understanding of your code, I guess a
CreateInstance should appear here. I might be wrong, though
Also, below, you might want to have your own implementation of
ISAXErrorHandler (which can be included in your SAX Handler class)
This would allow you to collect the error and decide later what to do (how
to send the information back to the client).
I might be wrong, as I am not familiar with the SAXErrorHandlerImpl
if (!pMc)
return S_ERROR;
hr = spReader->putContentHandler(pMc);
SAXErrorHandlerImpl * pEc =
new SAXErrorHandlerImpl();
hr = spReader->putErrorHandler(pEc);
static wchar_t URL[1000];
mbstowcs( URL, argv[1], 999 );
VARIANT MyVariant;
MyVariant.vt = VT_BSTR;
MyVariant.bstrVal =
(BSTR)m_RequestBuffer;// ERROR HERE!
hr = spReader->parse(MyVariant);
spReader->Release();//Do we need this here?
ATLTRACE("Node: %s Value:%d\n",pMc->Name,
pMc->Value);
}
On the other hand, given m_RequestBuffer as a dynamically
allocated memory according to the data length of client
POST, I have trouble in packing m_RequestBuffer into a
VARIANT to pass to parse(), because the compiler cannot
convert m_RequestBuffer from CHAR to BSTR (Please read the
comment in the program.) Is there an efficient way (e.g.
data type or class) to get client POST data and pass it to
spReader->parse() directly, without converting from WCS to
MBS or vice versa.

[Bogdan Crivat]
The Client POST data does not have to be copied. It is available as a stream
interface and
can be passed directly to the SAXXMLReader. See the following code snippet
for an example:

// Create a stream wrapper on top of the HTTP Server Context
CStreamOnServerContext s(m_pRequestInfo->pServerContext);
// Now create a variant that will contain the IUnknown of the IStream object
above
CComVariant varStream;
varStream = static_cast<IUnknown*>(&s);
HRESULT hr = spReader->parse(varStream);
If posible, please try to take a look at the atlsoap.h file coming with VS.
That file (the ATL Server SOAP implementation)
has to solve problems similar to the ones you have



Finally, do I have to do clean up
with "spReader->Release();" for the per-thread spReader?
[Bogdan Crivat]
No, you don't have to call an extra release. Basically, your code should
look like:
{
CComPtr<ISAXXMLReader> spReader;
m_spServiceProvider->QueryService(..., &spReader);
...
spReader->putContentHandler(...)
...
spReader->parse()
...
}
Let's assume that initially the ref count for the per- thread reader is 1.
QueryService will make it 2.
The destructor of the spReader smart pointer will call Release once and make
it back to 1, therefore ready for being used again on the same thread, with
different
data




Thank you very much.

-----Original Message-----
Hi

Mostly for SOAP purposes, ATL Server applications
already
provide a
per-thread ISAXXMLReader.
( You can disable this feature by defining #define ATL_NO_SOAP, but it is ON
by default)
You can access this per-thread ISAXXMLReader in your request handler with
code like below:

CComPtr<ISAXXMLReader> spReader;
HRESULT hRet =
m_spServiceProvider->QueryService(__uuidof (ISAXXMLReader),
__uuidof(ISAXXMLReader), &spReader)

Hope this helps,
and
confers no rights.
Please do not send email directly to this alias. It is for newsgroup
purposes only.

thanks,
bogdan




Hi,

In my current ATL server project, I have to parse the
input in the client application's request to find out
the different combination of parameters, instead of
using SOAP. For this reason, I am not using ATL server
web service project. On client side, I use POST to send
XML to web server. I know I should use ISAXXMLReader in
the server program. I also know that the parser can be
used for many different handlers in the DLL. I found some
example of SAX2 from Microsoft as standalone program.

ISAXXMLReader* pRdr = NULL;
HRESULT hr = CoCreateInstance(
__uuidof(SAXXMLReader),
NULL,
CLSCTX_ALL,
__uuidof(ISAXXMLReader),
(void **)&pRdr);
if(!FAILED(hr))
{
MyContent * pMc = new MyContent();
hr = pRdr->putContentHandler(pMc);
SAXErrorHandlerImpl * pEc =
new SAXErrorHandlerImpl();
hr = pRdr->putErrorHandler(pEc);
static wchar_t URL[1000];
mbstowcs( URL, argv[1], 999 );
wprintf(L"\nParsing document: %s\n", URL);
hr = pRdr->parseURL(URL);
printf("\nParse result code: %08x\n\n",hr);
pRdr->Release();
delete pMc;
}
This looks like a half COM program. Is this against
ATL Server project? How to make this per thread function?
What should I do to make it safe, thread-safe, no memory
leak, etc. Due to the lack of documents and books, I
cannot find more examples or information. Now, I still
have some trouble in using it in ATL server application.

Coud anyone help?

Thank you very much.

FS Liu



.


.
 
B

Bogdan Crivat [MSFT]

Hello,


For the construction issue
//hr = pContent.CoCreateInstance(
// __uuidof(MyContent), NULL,
// CLSCTX_INPROC_SERVER);
hr = spReader->putContentHandler(pContent);

This will work only if your class is a registered COM server (and you will
have to pass the GUID of the registered server in CoCreate)

Assuming you wrote a C++ class,

class MyContent : public ISAXContentHandler
{
virtual HRESULT startElement(.....)
.....
}
your code while handling request should look like one of the following:

1. {
MyContent content;
hr = spReader->putContentHandler((ISAXContentHandler*)&content);
...
spReader->parse(...)
...
hr = spReader->putContentHandler(NULL); // disable the reference to
the content handler


}

(or 2.)
{
CComPtr< ISAXContentHandler> spHandler;
GetAHandler(&spHandler)
hr = spReader->putContentHandler(spHandler);
...
spReader->parse(...)
...
hr = spReader->putContentHandler(NULL); // disable the reference to
the content handler


}
HRESULT GetAHandler( ISAXContentHandler** out_ppHandler)
{
MyContent * pNew = new MyContent;
*out_ppHandler = pNew;
return S_OK
}
In this latter case, make sure that Release on MyContent calls "delete
this" when the ref count reaches 0.




CComVariant varStream;
varStream = static_cast<IUnknown*>(&s);
ATLTRACE((char *)(varStream.bstrVal));
This will not work for a few reasons:
1 -
assigning an IUnknown* to a CComVariant will invoke CComVariant& operator
=(IUnknown* pSrc );
After this, the type of the variant is VT_UNKNOWN, so using
varStream.bstrVal in a trace is incorrect (and might lead to an access
violation)

2 -
varStream is a stream, that is an IStream implementationm which is
forward-only (can only be read once). ISAXXMLReader->parse will do this
If you would be able to trace the IStream, then ISAXXMLReader will start
parsing at the end of the stream and will find no content
The advantage of the stream approach is that the content is only read once
from the Server context (which means, from the client) and is not copied in
intermediary buffers.

If you want to do the trace, you have at least 3 options:
- (for a complete ATL trace) -- instead of using the stream copy everything
into a BSTR. Trace the BSTR then parse the BSTR to the ISAXXMLReader (the
way
you were initially handling the content). This will create at least one
supplementary copy of the content and might be slow, especially if the
content to be parsed is big

- (IMO, the best and simplest solution) Derive your own class from
CStreamOnServerContext, override the Read virtual with code like:

HRESULT __stdcall Read(void* pDest, ULONG nMaxLen, ULONG* pnRead)
{
HRESULT hRet =__super::Read( pDest, nMaxLen, pnRead);
if( SUCCEEDED(hRet) )
{
char* buff = new char[*pnRead + 1];
strncpy( buff, (char*)pDest, *pnRead);
buff[*pnRead] = 0;
ATLTRACE((char*)pDest);
}
return hRet;
}


- you could write an ISAPI filter that traces the content before getting to
your ISAPI DLL. See the ISAPIFilter sample coming with ATL Server for a
templatye of an ISAPI filter


Hope it work fine for you

--
--
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Please do not send email directly to this alias. It is for newsgroup
purposes only.

thanks,
bogdan




FS Liu said:
Hi, Bogdan,

Thank you very much for the valuable message. After I
declare
CComPtr <MyContent> pContent;
pContent is NULL. Yes, you are right. I should
CreateInstance after this line. So, I change my program
as (a simplified version):
CComPtr <ISAXXMLReader> spReader;
hr = m_spServiceProvider->QueryService(
__uuidof(ISAXXMLReader), &spReader);
CComPtr <MyContent> pContent;
//pContent = new MyContent();
//hr = pContent.CoCreateInstance(
// __uuidof(MyContent), NULL,
// CLSCTX_INPROC_SERVER);
hr = spReader->putContentHandler(pContent);
CStreamOnServerContext s(m_pRequestInfo-
pServerContext);
CComVariant varStream;
varStream = static_cast<IUnknown*>(&s);
ATLTRACE((char *)(varStream.bstrVal));
hr = spReader->parse (varStream);

When I use
pContent = new MyContent();
to create the instance, VS.NET compiler reports a message
saying "cannot instanciate the class" (I am using a
Japanese version. I don't know the exact wording of the
message in English). Does this mean that I have to include
some header files from VS.NET, such as msxml2.h or
something else? When I use
hr = pContent.CoCreateInstance(__uuidof
(MyContent), NULL, CLSCTX_INPROC_SERVER);
the compiler also complains: there is no associated GUID.
I read atlsoap.h and found the parseFault() function. It
is similar to the above code, except the creation of
content handler. I tried several ways to create an
instance, but failed.

I feel I just have one step further to clearify this
issue, but cannot find enough document. Could you help? By
the way, "ATLTRACE((char *)(varStream.bstrVal));" does
not print the XML string. Do you know why?

Thank you very much.

FS Liu



-----Original Message-----
Please see inlines (look for [Bogdan Crivat])
Hope this helps, let me know if you run into any other issues

--
--
--
This posting is provided "AS IS" with no warranties, and confers no rights.
Please do not send email directly to this alias. It is for newsgroup
purposes only.

thanks,
bogdan




FS Liu said:
Hi, Bogdan,

Thank you so much for the example. I still have a problem
about the use of content handler class, MyContent. All the
Microsoft examples use
MyContent * pMc = new MyContent();
I defined a content handler that has member variables for
pairs of node and value. After running spReader->parse (),
I use the resultant pairs in the rest of the program. Is
it a better idea to use
CComPtr<MyContent> pMc;
in ATL Server application project for easier memory
management? To do so, is there any special requirement to
define the content handler MyContent? Here is my code:

[Bogdan Crivat] -- Yes, this should be a smart pointer. The SAX Reader will
AddRef and Release the handler repeatedly. CComPtr is the right way of
ensuring the
life span of the handler object

CComHeapPtr<CHAR> m_RequestBuffer;// buffer for
client POST data.
CComPtr<ISAXXMLReader> spReader;
HRESULT hr = m_spServiceProvider->QueryService(
__uuidof(ISAXXMLReader), &spReader)
if(!FAILED(hr))
{
CComPtr<MyContent> pMc;


[Bogdan Crivat] -- Based on my understanding of your code, I guess a
CreateInstance should appear here. I might be wrong, though
Also, below, you might want to have your own implementation of
ISAXErrorHandler (which can be included in your SAX Handler class)
This would allow you to collect the error and decide later what to do (how
to send the information back to the client).
I might be wrong, as I am not familiar with the SAXErrorHandlerImpl
if (!pMc)
return S_ERROR;
hr = spReader->putContentHandler(pMc);
SAXErrorHandlerImpl * pEc =
new SAXErrorHandlerImpl();
hr = spReader->putErrorHandler(pEc);
static wchar_t URL[1000];
mbstowcs( URL, argv[1], 999 );
VARIANT MyVariant;
MyVariant.vt = VT_BSTR;
MyVariant.bstrVal =
(BSTR)m_RequestBuffer;// ERROR HERE!
hr = spReader->parse(MyVariant);
spReader->Release();//Do we need this here?
ATLTRACE("Node: %s Value:%d\n",pMc->Name,
pMc->Value);
}
On the other hand, given m_RequestBuffer as a dynamically
allocated memory according to the data length of client
POST, I have trouble in packing m_RequestBuffer into a
VARIANT to pass to parse(), because the compiler cannot
convert m_RequestBuffer from CHAR to BSTR (Please read the
comment in the program.) Is there an efficient way (e.g.
data type or class) to get client POST data and pass it to
spReader->parse() directly, without converting from WCS to
MBS or vice versa.

[Bogdan Crivat]
The Client POST data does not have to be copied. It is available as a stream
interface and
can be passed directly to the SAXXMLReader. See the following code snippet
for an example:

// Create a stream wrapper on top of the HTTP Server Context
CStreamOnServerContext s(m_pRequestInfo->pServerContext);
// Now create a variant that will contain the IUnknown of the IStream object
above
CComVariant varStream;
varStream = static_cast<IUnknown*>(&s);
HRESULT hr = spReader->parse(varStream);
If posible, please try to take a look at the atlsoap.h file coming with VS.
That file (the ATL Server SOAP implementation)
has to solve problems similar to the ones you have



Finally, do I have to do clean up
with "spReader->Release();" for the per-thread spReader?
[Bogdan Crivat]
No, you don't have to call an extra release. Basically, your code should
look like:
{
CComPtr<ISAXXMLReader> spReader;
m_spServiceProvider->QueryService(..., &spReader);
...
spReader->putContentHandler(...)
...
spReader->parse()
...
}
Let's assume that initially the ref count for the per- thread reader is 1.
QueryService will make it 2.
The destructor of the spReader smart pointer will call Release once and make
it back to 1, therefore ready for being used again on the same thread, with
different
data




Thank you very much.


-----Original Message-----
Hi

Mostly for SOAP purposes, ATL Server applications already
provide a
per-thread ISAXXMLReader.
( You can disable this feature by defining #define
ATL_NO_SOAP, but it is ON
by default)
You can access this per-thread ISAXXMLReader in your
request handler with
code like below:

CComPtr<ISAXXMLReader> spReader;
HRESULT hRet =
m_spServiceProvider->QueryService(__uuidof (ISAXXMLReader),
__uuidof(ISAXXMLReader), &spReader)

Hope this helps,

--
--
--
This posting is provided "AS IS" with no warranties, and
confers no rights.
Please do not send email directly to this alias. It is
for newsgroup
purposes only.

thanks,
bogdan




Hi,

In my current ATL server project, I have to parse the
input in the client application's request to find out
the different combination of parameters, instead of
using SOAP. For this reason, I am not using ATL server
web service project. On client side, I use POST to send
XML to web server. I know I should use ISAXXMLReader in
the server program. I also know that the parser can be
used for many different handlers in the DLL. I found
some
example of SAX2 from Microsoft as standalone program.

ISAXXMLReader* pRdr = NULL;
HRESULT hr = CoCreateInstance(
__uuidof(SAXXMLReader),
NULL,
CLSCTX_ALL,
__uuidof(ISAXXMLReader),
(void **)&pRdr);
if(!FAILED(hr))
{
MyContent * pMc = new MyContent();
hr = pRdr->putContentHandler(pMc);
SAXErrorHandlerImpl * pEc =
new SAXErrorHandlerImpl();
hr = pRdr->putErrorHandler(pEc);
static wchar_t URL[1000];
mbstowcs( URL, argv[1], 999 );
wprintf(L"\nParsing document: %s\n", URL);
hr = pRdr->parseURL(URL);
printf("\nParse result code: %08x\n\n",hr);
pRdr->Release();
delete pMc;
}
This looks like a half COM program. Is this against
ATL Server project? How to make this per thread
function?
What should I do to make it safe, thread-safe, no memory
leak, etc. Due to the lack of documents and books, I
cannot find more examples or information. Now, I still
have some trouble in using it in ATL server application.

Coud anyone help?

Thank you very much.

FS Liu



.


.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top