everyone. I know Microsoft have given an example about the save method of IXMLDOMDocument like this:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd874226(v=vs.85).aspx
But when I changed the parameter of save to a variable like CString or char* instead of a constant, I got an exception in the save method like this:
"Unhandled exception in VisualADS.exe: 0xC0000005: Access Violation."
The exception position is:
#pragma implementation_key(76)
inline HRESULT MSXML2::IXMLDOMDocument::save ( const _variant_t & destination ) {
HRESULT _hr = raw_save(destination);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return _hr;
}
This is a MFC MBCS project in Visual Studio 6, here's my code, thx!
CString strFilePathName = ar.GetFile()->GetFilePath();
CComBSTR ccbsFilePathName(strFilePathName);
CComVariant ccvFilePathName(ccbsFilePathName);
hr = pXMLDoc->save(ccvFilePathName);
The variant you pass to IXMLDOMDocument::save has to carry a BSTR. If your project is an UNICODE one, there is great chances that you'll have no conversions to do, and no reasons to crash using weird attempts.
If you are in a MBCS project, things are different: you have to somehow convert the file name from MBCS to UNICODE before using it in OLE/COM. I suggest doing so using the CComBSTR class
CString strFilePathName;
[...]
CComBSTR ccbsFilePathName( strFilePathName );
CComVariant ccvFilePathName( ccbsFilePathName );
hr = pXMLDoc->save( ccvFilePathName );
Related
I am trying to write a CLI wrapper around some low-level COM-related calls. One of the operations that I need to do specifically is to get a specific value from a PROPVARIANT, i.e.:
pwszPropName = varPropNames.calpwstr.pElems[dwPropIndex];
where pwszPropName is documented to be an LPWSTR type and dwPropIndex is a DWORD value passed into the function by the user.
I have a native function defined as follows:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, wchar_t *PropertyName)
I would like to return the value of pwszPropName via *PropertyName.
Is the wchar_t* type the best way to do this, and would I need to pin *PropertyName in my CLI to ensure it does not move in memory? Do I need to define the length of *PropertyName before passing it to native code (buffer)?
If wchar_t* is the right variable type to pass into the native function, what is the proper conversion of LPWSTR to whar_t*, and how then would you convert that value to System::String?
I have tried a number of different techniques over the past few days and can't seem to get anything right.
------------UPDATE------------
Here is my full code. First, the CLI:
String^ MetadataEditor::GetPropertyNameByID(unsigned int ID)
{
LPWSTR mPropertyName = L"String from CLI";
m_pCEditor->GetPropertyNameByID(ID, mPropertyName);
//Convert return back to System::String
String^ CLIString = gcnew String(mPropertyName);
return CLIString;
}
And the native code:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, LPWSTR PropertyName)
{
HRESULT hr = S_OK;
LPWSTR myPropName;
PROPVARIANT varNames;
PropVariantInit(&varNames);
hr = m_pMetadata->GetAllPropertyNames(&varNames);
if(hr != S_OK)
{
PropVariantClear(&varNames);
return hr;
}
myPropName = varNames.calpwstr.pElems[ID];
PropertyName = myPropName;
PropVariantClear(&varNames);
return hr;
}
It doesn't seem like the value (myPropName) is set properly and/or sustained back into the CLI function because the CLI returns the value I set on mPropertyName before calling the native function.. I'm not sure why or how to fix this.
UPDATE!!!!
I suspected my problem had something to do with variables going out of scope. So I changed the C++ function definition as follows:
LPWSTR GetPropertyNameByID(DWORD ID, HRESULT ErrorCode);
After adjusting the CLI as well, I now get a value returned, but the first character is incorrect, and in fact can be different with every call. I tried using ZeroMemory() in the native class before assigning the output of the PROPVARIANT to the variable (ZeroMemory(&myPropName, sizeof(myPropName +1)); but still no luck.
You can design unmanaged function by the following way:
HRESULT CMetadataEditor::GetPropertyNameByID(DWORD ID, LPWSTR PropertyName, size_t size)
{
....
wcscpy(PropertyName, varNames.calpwstr.pElems[ID]); // or wcsncpy
...
}
PropertyName is the buffer allocated by caller, size is its size. Inside the function wcscpy or wcsncpy the string varNames.calpwstr.pElems[ID] to PropertyName. Client code:
WCHAR mPropertyName[100];
m_pCEditor->GetPropertyNameByID(ID, mPropertyName, sizeof(mPropertyName)/sizeof(mPropertyName[0]));
Think, for example, how GetComputerName API is implemented, and do the same
From book ATL Internals, I knew BSTR is different from OLECHAR*, and there are CComBSTR and CString for BSTR.
According MSDN Allocating and Releasing Memory for a BSTR, I knew memory management responsibility for caller/callee.
Take this line from MSDN,
HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)
I still do not know how to handle bstr properly in my implementation. Since I still have a basic question for BSTR -- should we treat bstr as a value (like int) or as a reference (like int*), at least on COM interface boundary.
I want to convert BSTR as soon as possible to CString/CComBSTR in my implementation. Value or Reference semantic will be totally different case for the conversion. I've digged into CComBSTR.Attach, CComBSTR.AssignBSTR, etc. But the code cannot solve my doubts.
MSDN CComBSTR.Attach has some code snip, I feel it is wrong since it is not obey Allocating and Releasing Memory for a BSTR. ATL Internals said SetSysString will 'free the original BSTR passed in', if I used it, it will violate BSTR argument convention, just like CComBSTR.Attach.
All in all, I want to using CString to handle raw BSTR in implementation, but do not know the correct way...I've written some just work code in my projects, but I always feel nervous since I don't know whether I am correct.
Let me talk coding language
HRESULT CMyWebBrowser::put_StatusText(BSTR bstr)
{
// What I do NOT know
CString str1; // 1. copy bstr (with embeded NUL)
CString str2; // 2. ref bstr
// What I know
CComBSTR cbstr1;
cbstr1.AssignBSTR(bstr); // 3. copy bstr
CComBSTR cbstr2;
cbstr2.Attach(bstr); // 4. ref bstr, do not copy
// What I do NOT know
// Should we copy or ref bstr ???
}
CComBSTR is just a RAII wrapper around raw BSTR. So feel free to use CComBSTR instead of raw BSTR to help writing code that is exception-safe, that makes it harder to leak resources (i.e. the raw BSTR), etc.
If the BSTR is an input parameter, it's just like a const wchar_t* (with length prefixed, and potentially some NULs L'\0' characters inside). If the BSTR doesn't have NULs embedded inside, you can simply pass it to a CString constructor, that will make a deep-copy of it, and you can locally work with your CString. Modifications to that CString won't be visible on the original BSTR. You can use std::wstring as well (and note that std::wstring can handle embedded NULs as well).
void DoSomething(BSTR bstrInput)
{
std::wstring myString(bstrInput);
// ... work with std::wstring (or CString...) inside here
}
Instead, if the BSTR is an output parameter, then it is passed using another level of indirection, i.e. BSTR*. In this case, you can use CComBSTR::Detach() inside your method to release the BSTR safely wrapped into the CComBSTR, and transfer its ownership to the caller:
HRESULT DoSomething( BSTR* pbstrOut )
{
// Check parameter pointer
if (pbstrOut == nullptr)
return E_POINTER;
// Guard code with try-catch, since exceptions can't cross COM module boundaries.
try
{
std::wstring someString;
// ... work with std::wstring (or CString...) inside here
// Build a BSTR from the ordinary string
CComBSTR bstr(someString.c_str());
// Return to caller ("move semantics", i.e. transfer ownership
// from current CComBSTR to the caller)
*pbstrOut = bstr.Detach();
// All right
return S_OK;
}
catch(const std::exception& e)
{
// Log exception message...
return E_FAIL;
}
catch(const CAtlException& e)
{
return e; // implicit cast to HRESULT
}
}
Basically, the idea is to use BSTR (wrapped in a RAII class like CComBSTR) only at the boundary, and do the local work using std::wstring or CString.
As a "bouns reading", consider Eric Lippert's guide to BSTR semantics.
Having BSTR on input, you are not responsible to release it. Converting to CString is easy:
CString sValue(bstr);
or, if you prefer to keep Unicode characters on MBCS build:
CStringW sValue(bstr);
If you need to convert back when you have [out] parameter, you do (simple version):
VOID Foo(/*[out]*/ BSTR* psValue)
{
CString sValue;
*psValue = CComBSTR(sValue).Detach();
}
Full version is:
STDMETHODIMP Foo(/*[out]*/ BSTR* psValue)
{
_ATLTRY
{
ATLENSURE_THROW(psValue, E_POINTER); // Parameter validation
*psValue = NULL; // We're responsible to initialize this no matter what
CString sValue;
// Doing our stuff to get the string value into variable
*psValue = CComBSTR(sValue).Detach();
}
_ATLCATCH(Exception)
{
return Exception;
}
return S_OK;
}
I have a need for a COM object that generates a GUID. I am a C# developer, but this will be deployed in a unix environment, so I'm thinking I need to build it in C++. This is my first Visual C++ project, and I'm having some trouble finishing it out.
Steps I've taken:
Created a new ATL project in Visual Studio (Dynamic-link library - no other options)
Right-click project -> Add class -> ATL Simple Object (Short name: GuidGenerator; ProgID: InfaGuidGenerator)
View -> ClassView -> IGuidGenerator -> Add Method (Method Name: Generate; Parameter Type: BSTR* [out]; Parameter Name: retGuid)
Added Boost to get the platform independent UUID generator.
// GuidGenerator.cpp : Implementation of CGuidGenerator
#include "stdafx.h"
#include "GuidGenerator.h"
#include <boost/lexical_cast.hpp>
#include <boost/uuid/uuid.hpp> // uuid class
#include <boost/uuid/uuid_generators.hpp> // generators
#include <boost/uuid/uuid_io.hpp> // streaming operators etc.
STDMETHODIMP CGuidGenerator::Generate(BSTR* retGuid)
{
boost::uuids::uuid uuid = boost::uuids::random_generator()();
std::string uuidStr = boost::lexical_cast<std::string>(uuid);
//not really sure what to do from here.
//I've tried to convert to BSTR.
//When I assign the resulting value to retGuid, I often get an error:
//A value of type BSTR cannot be assigned to an entity of type BSTR*
return S_OK;
}
Can anyone provide me some guidance on the next step?
Thanks.
Edit from comments:
I have already tried to convert to BSTR using the following, but I get an error:
STDMETHODIMP CGuidGenerator::Generate(BSTR* retGuid)
{
boost::uuids::uuid uuid = boost::uuids::random_generator()();
std::string uuidStr = boost::lexical_cast<std::string>(uuid);
int wslen = ::MultiByteToWideChar(CP_ACP, 0 /* no flags */,
uuidStr.data(), uuidStr.length(),
NULL, 0);
BSTR wsdata = ::SysAllocStringLen(NULL, wslen);
::MultiByteToWideChar(CP_ACP, 0 /* no flags */,
uuidStr.data(), uuidStr.length(),
wsdata, wslen);
retGuid = wsdata;
//ERROR: A value of type BSTR cannot be assigned to an entity of type BSTR*
return S_OK;
}
Assuming that std::string uuidStr is your string you want to return as BSTR output parameter, consider code like this:
#include <atlbase.h> // for CComBSTR
#include <atlconv.h> // for CA2W
STDMETHODIMP CGuidGenerator::Generate(BSTR* retGuid)
{
try
{
....
// Convert uuidStr from ASCII to Unicode
CA2W wszUuid( uuidStr.c_str() );
// Build a COM BSTR from the Unicode string
CComBSTR bstrUuid( wszUuid );
// Return the BSTR as output parameter
*retGuid = bstrUuid.Detach();
// All right
return S_OK;
}
//
// Catch exceptions and convert them to HRESULTs,
// as C++ exceptions can't cross COM module boundaries.
//
catch(const CAtlException& ex)
{
return static_cast<HRESULT>(ex);
}
catch(const std::exception& ex)
{
// May log the exception message somewhere...
return E_FAIL;
}
}
Note how a RAII helper class like CA2W simplifies the conversion from ASCII to Unicode, and CComBSTR simplifies the management of raw BSTRs.
This Microsoft article on COM under Unix might help more generally.
As to the next step, a BSTR is not your usual string; .NET hides this complexity from you. A BSTR is a specialised string that's intended to be marshalled across thread/process boundaries.
Have a look at this answer to see how to convert your std::string to a BSTR.
What is the correct way of doing this:
_bstr_t description;
errorInfo->GetDescription( &description.GetBSTR() );
or:
_bstr_t description;
errorInfo->GetDescription( description.GetAddress() );
Where IError:GetDescription is defined as:
HRESULT GetDescription (BSTR *pbstrDescription);
I know I could easily do this:
BSTR description= SysAllocString (L"Whateva"));
errorInfo->GetDescription (&description);
SysFreeString (description);
Thanks
The BSTR is reference counted, I seriously doubt that will work right if you use GetAddress(). Sadly the source code isn't available to double-check that. I've always done it like this:
BSTR temp = 0;
HRESULT hr = p->GetDescription(&temp);
if (SUCCEEDED(hr)) {
_bstr_t wrap(temp, FALSE);
// etc..
}
To follow up on #Hans's answer - the appropriate way to construct the _bstr_t depends on whether GetDescription returns you a BSTR that you own, or one that references memory you don't have to free.
The goal here is to minimize the number of copies, but also avoid any manual calls to SysFreeString on the returned data. I would modify the code as shown to clarify this:
BSTR temp = 0;
HRESULT hr = p->GetDescription(&temp);
if (SUCCEEDED(hr)) {
_bstr_t wrap(temp, false); // do not copy returned BSTR, which
// will be freed when wrap goes out of scope.
// Use true if you want a copy.
// etc..
}
A late answer that may not apply to earlier (or later) versions of Visual Studio; however,
VS 12.0 has the _bstr_t implementation inline, and evidently an internal Data_t instance is created with a m_RefCount of 1 when calling GetBSTR() on a virgin _bstr_t. So the _bstr_t lifecycle in your first example looks to be okay:
_bstr_t description;
errorInfo->GetDescription( &description.GetBSTR() );
But if _bstr_t is dirty, the existing internal m_wstr pointer will be overwritten, leaking the previous memory it referenced.
By using the following operator&, a dirty _bstr_t can be used given that it's first cleared via Assign(nullptr). The overload also provides the convenience of utilizing the address operator instead of GetBSTR();
BSTR *operator&(_bstr_t &b) {
b.Assign(nullptr);
return &b.GetBSTR();
}
So, your first example could instead look like the following:
_bstr_t description(L"naughty");
errorInfo->GetDescription(&description);
This evaluation was based on comutil.h from VS 12.0.
_bstr_t (and its ATL sibling CComBSTR) are resource owners of BSTR. Spying from the code it seems that 'GetAddress' is specifically designed for the use case of working with BSTR output parameters where it is expected that client frees the BSTR.
Using 'GetAddress()' is not equivalent to using '&GetBSTR()' in case the _bstr_t already owns a BSTR. MSDN states: 'Frees any existing string and returns the address of a newly allocated string.'.
_bstr_t bstrTemp;
HRESULT hr = p->GetDescription(bstrTemp.GetAddress());
Caveat: this specific use case of 'GetAddress' is not stated in the documentation; it is my deduction from looking at the source code and experience with its ATL counter part CComBSTR.
Since user 'caoanan' questioned this solution, I paste here the source code Microsoft:
inline BSTR* _bstr_t::GetAddress()
{
Attach(0);
return &m_Data->GetWString();
}
inline wchar_t*& _bstr_t::Data_t::GetWString() throw()
{
return m_wstr;
}
inline void _bstr_t::Attach(BSTR s)
{
_Free();
m_Data = new Data_t(s, FALSE);
if (m_Data == NULL) {
_com_issue_error(E_OUTOFMEMORY);
}
}
inline _bstr_t::Data_t::Data_t(BSTR bstr, bool fCopy)
: m_str(NULL), m_RefCount(1)
{
if (fCopy && bstr != NULL) {
m_wstr = ::SysAllocStringByteLen(reinterpret_cast<char*>(bstr),
::SysStringByteLen(bstr));
if (m_wstr == NULL) {
_com_issue_error(E_OUTOFMEMORY);
}
}
else {
m_wstr = bstr;
}
}
My answer is also late. Suppose you have the signature HRESULT PutDescription (BSTR NewDescription);. In that case do the following
_bstr_t NewAdvice = L"Great advice!";
HRESULT hr1 = PutDescription(NewAdvice.GetBSTR());
By the rules of COM, the function PutDescription is not allowed to change or even destroy the passed BSTR.
For the opposite HRESULT GetDescription (BSTR *pActualDescription); pass a virgin _bstr_t by means of the function GetAddress():
_bstr_t GetAdvice;
HRESULT hr2 = GetDescription(GetAdvice.GetAddress());
The function GetAddress() frees any existing string and returns the address of a newly allocated string. So, if you pass a _bstr_t that has some content, this content will be freed and is therefore lost. The same happens to all _bstr_ts that share the same BSTR. But I think this is a stupid thing to do. Why passing an argument with content to a function that is supposed to change that content?
_bstr_t GetAdvice = L"This content will not survive the next function call!";
HRESULT hr = GetDescription(GetAdvice.GetAddress());
A real moron might even pass a _bstr_t that is assigned to a raw BSTR:
BSTR Bst = ::SysAllocString(L"Who would do that?");
_bstr_t GetDescr;
GetDescr.Attach(Bst);//GetDescr wraps Bst, no copying!
HRESULT hr = GetDescription(GetDescr.GetAddress());
In that case GetDescr gets the expected value but the content of Bst is unpredictable.
int GetDataStr(_bstr_t & str) override {
BSTR data = str.Detach();
int res = m_connection->GetDataStr( &data );
str.Attach(data);
return res;
}
I am using this code to sink events in a IWebBrowser2 webbrowser on c++:
STDMETHODIMP AdviseSink::Invoke(DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS* pDispParams,
VARIANT* pVarResult,
EXCEPINFO* pExcepInfo,
UINT* puArgErr)
{
if (!pDispParams)
return DISP_E_PARAMNOTOPTIONAL;
switch (dispIdMember)
{
case DISPID_DOCUMENTCOMPLETE:
{
DocumentComplete(pVarResult);
return S_OK;
}
case DISPID_NAVIGATECOMPLETE2:
return S_OK;
default:
return DISP_E_MEMBERNOTFOUND;
}
return S_OK;
}
void DocumentComplete(VARIANT *url)
{
std::string strValue = (char*)_bstr_t(url);
}
When calling (void)DocumentComplete I get this error:
*Unhandled exception at 0x7c812afb in webhost.exe: Microsoft C++ exception: _com_error at memory location 0x0012ed50.*
If comment the line on DocumentComplete, it doesn't show any errors. Also try..catch blocks doens't catch the exception.
What I am trying to do is to use Variant * url to compare it with a std::string.
How can I do this?
You are using the return value (an [out] parameter) as one of the event parameters. This will cause bstr_t to throw a com_error exception because the VARIANT doesn't contain a BSTR.
See the MSDN documentation for the correct DocumentComplete signature.
The event parameters are available from pDispParams not pVarResult. Assuming that it's not called with named arguments (and this event shouldn't be), the url will be available at pDispParams->rgvarg[0] and the window/frame at pDispParams->rgvarg[1]. Parameters are in the opposite order in the rgvarg array as they're declared in the idl.
If you can, I recommend instead using ATL's IDispEventSimpleImpl to implement COM event interfaces in C++ instead of implementing IDispatch yourself.
http://msdn.microsoft.com/en-us/library/9k3ebasf(v=VS.100).aspx
the _bstr_t constructor takes only reference of VARIANT, instead of pointer to it.
YeenFei gave half of the answer. The other half is that after you get your bstr, it will point to a Unicode string not to an ANSI string. If you want to get an ANSI string, you have to do it by converting the string from Unicode to ANSI, not by converting the pointer.