CString and COM
-
I'm pretty new to COM programming so here goes my question. I've written a component that has some properties. One is written like
STDMETHODIMP CPopClient::get_Response(BSTR *pVal)
{
*pVal = (BSTR) m_bsResponse; // m_bsResponse is a CComBSTRreturn S\_OK;
}
Would this be the correct way to use it
IPop->get_Response (&message.AllocSysString ()); // message is a CString
Thinking about this I see a problem in that if the CString is null then I'm not allocating anything. So I guess I'm needing to know how I would call the above property from MFC. Thanks. - Aaron
-
I'm pretty new to COM programming so here goes my question. I've written a component that has some properties. One is written like
STDMETHODIMP CPopClient::get_Response(BSTR *pVal)
{
*pVal = (BSTR) m_bsResponse; // m_bsResponse is a CComBSTRreturn S\_OK;
}
Would this be the correct way to use it
IPop->get_Response (&message.AllocSysString ()); // message is a CString
Thinking about this I see a problem in that if the CString is null then I'm not allocating anything. So I guess I'm needing to know how I would call the above property from MFC. Thanks. - Aaron
No, you need to use a BSTR implicitly. BSTR bstrVal; IPop->get_Response (bstrVal); Your get_Response() implementation should be responsible for allocating storage. Your "client" must therefore free the BSTR when its finished with it. So, remember to call something like: ::SysFreeString(bstrVal); Hope that helps!
-
I'm pretty new to COM programming so here goes my question. I've written a component that has some properties. One is written like
STDMETHODIMP CPopClient::get_Response(BSTR *pVal)
{
*pVal = (BSTR) m_bsResponse; // m_bsResponse is a CComBSTRreturn S\_OK;
}
Would this be the correct way to use it
IPop->get_Response (&message.AllocSysString ()); // message is a CString
Thinking about this I see a problem in that if the CString is null then I'm not allocating anything. So I guess I'm needing to know how I would call the above property from MFC. Thanks. - Aaron
Aaron, If you're using #import for your COM object, then why not use the nice wrappers implemented for you. e.g.
\_bstr\_t bstrValue = IPop->GetResponse();
The wrapper tests for failed HRESULTS and also uses _bstr_t which handles Allocs and Deallocs for you. Hope this helps, Andy
-
Aaron, If you're using #import for your COM object, then why not use the nice wrappers implemented for you. e.g.
\_bstr\_t bstrValue = IPop->GetResponse();
The wrapper tests for failed HRESULTS and also uses _bstr_t which handles Allocs and Deallocs for you. Hope this helps, Andy
AndyQ wrote: _bstr_t bstrValue = IPop->GetResponse(); Can I use that even though the get_Response is implemeted with the return being a pointer parameter passed in, and the return is an HRESULT? Thanks for the information on the _bstr_t class. - Aaron
-
No, you need to use a BSTR implicitly. BSTR bstrVal; IPop->get_Response (bstrVal); Your get_Response() implementation should be responsible for allocating storage. Your "client" must therefore free the BSTR when its finished with it. So, remember to call something like: ::SysFreeString(bstrVal); Hope that helps!
Thank you for the information. - Aaron
-
AndyQ wrote: _bstr_t bstrValue = IPop->GetResponse(); Can I use that even though the get_Response is implemeted with the return being a pointer parameter passed in, and the return is an HRESULT? Thanks for the information on the _bstr_t class. - Aaron
Aaron, If you are using #import you should get two files in the project directory, e.g. Pop.tli Pop.thi These are implementation and header files from the import process. Now you should get different versions of the same method calls. You'll have the 'raw' call that returns the HRESULT as you describe, but there should be another version that simplifies things, an example may look like:
inline _bstr_t IPop::GetResponse( ) {
BSTR _result;
HRESULT _hr = get_Response(&_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _bstr_t(_result, false);
}Look for the files in your project directory (or debug/release directory) and look through them. Hope this helps, Andy
-
Aaron, If you are using #import you should get two files in the project directory, e.g. Pop.tli Pop.thi These are implementation and header files from the import process. Now you should get different versions of the same method calls. You'll have the 'raw' call that returns the HRESULT as you describe, but there should be another version that simplifies things, an example may look like:
inline _bstr_t IPop::GetResponse( ) {
BSTR _result;
HRESULT _hr = get_Response(&_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _bstr_t(_result, false);
}Look for the files in your project directory (or debug/release directory) and look through them. Hope this helps, Andy
Ah, that makes a lot of sense now. I wasn't using #import, but that seems like a much better way to do it. I'll give that a go. Thanks very much for the help Andy. - Aaron
-
I'm pretty new to COM programming so here goes my question. I've written a component that has some properties. One is written like
STDMETHODIMP CPopClient::get_Response(BSTR *pVal)
{
*pVal = (BSTR) m_bsResponse; // m_bsResponse is a CComBSTRreturn S\_OK;
}
Would this be the correct way to use it
IPop->get_Response (&message.AllocSysString ()); // message is a CString
Thinking about this I see a problem in that if the CString is null then I'm not allocating anything. So I guess I'm needing to know how I would call the above property from MFC. Thanks. - Aaron
Hi Aaron, There is an error in the way you are returning the string, what you are doing is passing the address of the string contained on m_bsResponse to the caller, the problem there is if the instance of CPopClient is destroyed the client will end having an address to a string that is not longer valid. So, what you should do is create a copy of the string and return the address of the copy. Remember BSTR is a pointer to a wide character string, so BSTR * is a pointer to a pointer!!!
STDMETHODIMP CPopClient::get_Response(BSTR *pVal)
{
*pVal = m_bsResponse.Copy(); // m_bsResponse is a CComBSTR
return S_OK;
}And the client should do something like this to call it
BSTR sResponse;
IPop->get_Response(&sResponse);... do something with the string
//Free the string
SysFreeString(sResponse);Fabian