I'm trying to add a simple .mp3 file to the iTunes library but my program keeps crashing when I call AddFile(). However, when I call get_Tracks() it returns a valid pointer, so I suppose the pointer to IITLibraryPlaylist is valid. What am I doing wrong?
IiTunes* p_iTunes;
IITLibraryPlaylist* p_Library;
IITOperationStatus* status;
IITTrackCollection* iTrackCollection;
CoInitialize(0);
if (FAILED(CoCreateInstance(CLSID_iTunesApp, NULL, CLSCTX_LOCAL_SERVER, IID_IiTunes, (PVOID *)&p_iTunes))){
p_iTunes->Release();
CoUninitialize();
}
else{
p_iTunes->get_LibraryPlaylist(&p_Library);
p_Library->get_Tracks(&iTrackCollection); // This works, so I suppose p_Library is valid..
long trackCount = 0;
iTrackCollection->get_Count(&trackCount);
p_Library->AddFile(L"C:\\asd\asd.mp3",&status); // crashes here
}
The problem is you pass WCHAR* instead of properly allocated BSTR and that leads to undefined behavior.
You should first allocate a BSTR using SysAllocString() (don't forget to release the string later) or better yet use a wrapper class like ATL::CComBSTR or _bstr_t for managing BSTR lifetime.
Related
I am learning COM through C++. From MSDN:
Applications are required to use CoInitializeEx before they make any
other COM library calls except for memory allocation functions.
The memory allocation functions is CoTaskMemAlloc and CoTaskMemFree in my opinion.
But I see, my "Hello World" works fine with and without the CoInitializeEx and CoUninitialize functions calling. In my code I use the StringFromCLSID function which is declared in the combaseapi.h header. So, it is a COM function in my opinion. My code:
/* entry_point.cpp */
#include "Tools.h"
#include <objbase.h>
int main(){
HRESULT hr = ::CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hr)){
trace("Can't initialize COM for using in the current thread.");
keep_window_opened();
return 1;
}
// {D434CF7D-2CDD-457A-A4EF-5822D629CE83}
static const CLSID clsid =
{ 0xd434cf7d, 0x2cdd, 0x457a, {
0xa4, 0xef, 0x58, 0x22, 0xd6, 0x29, 0xce, 0x83 } };
const size_t SIZE = 39;
wchar_t* wch = nullptr;
hr = ::StringFromCLSID(clsid, &wch);
if (FAILED(hr)){
trace("Can't convert CLSID to wchar_t array.");
}
else{
trace("CLSID converted to wchar_t array.");
char mch[SIZE];
size_t count = 0;
int result = ::wcstombs_s(&count, mch, wch, SIZE);
if (result){
trace("Can't convert wchar_t array to char array.");
}
else{
trace(mch);
}
::CoTaskMemFree(wch);
}
::CoUninitialize();
keep_window_opened();
return 0;
}
If I remove the calls of CoInitializeEx and CoUninitialize functions, then my code works still. I expected it will not work...
Why StringFromCLSID work even without the calling of CoInitializeEx before?
Thank you.
StringFromCLSID is basically a printout of GUID value (bytes) into string, then formatting it nicely with hyphens and braces. There is nothing else involved and hence COM initialization is not really needed for this call to succeed.
You have to do CoInitialize/CoInitializeEx to be safe, but not doing it you don't necessarily hit a problem right away.
Why StringFromCLSID work even without the calling of CoInitializeEx before?
The key information is stated right in the documentation.
CoInitializeEx function:
You need to initialize the COM library on a thread before you call any of the library functions except ... the memory allocation functions. Otherwise, the COM function will return CO_E_NOTINITIALIZED.
StringFromCLSID function:
StringFromCLSID calls the StringFromGUID2 function to convert a globally unique identifier (GUID) into a string of printable characters.
The caller is responsible for freeing the memory allocated for the string by calling the CoTaskMemFree function.
StringFromCLSID() returns a dynamically allocated string. We can infer from the highlighted sentence above that the memory is allocated using CoTaskMemAlloc() - which is explicitly documentated as not requiring CoInitializeEx().
StringFromGUID2() formats GUID data into a caller-specified memory block. Formatting a string does not require COM functionality. The wsprintfW(), StringCbPrintfW(), or other equivalent function would suffice. So CoInitializeEx() should not be required for StringFromGUID2(), even though this is not explicitly documented. I think it would be pretty short-sighted for Microsoft to not use one of their many available string formatting functions to implement StringFromGUID2(). So I think it should be safe to say that CoInitializeEx() is not a requirement for this (unless Microsoft says otherwise).
The GUID structure simply contains a few numbers and bytes. Declaring and using a GUID is not dependent on the COM library. You can freely use a GUID in your code all you want without touching COM at all - unless you want to generate a new GUID, in which case the CoInitializeEx() requirement for CoCreateGUID() is blurry as CoCreateGUID() is in the COM library but is explicitly documented as simply calling UuidCreate(), which is in the RPC library instead.
So that is why you can call StringFromCLSID() without calling CoInitializeEx() first. A GUID on its own does not require COM initialization. The string is being allocated with a memory function that does not require COM initialization. And the string is being formatted in a manner that most likely does not require COM initialization.
I have written a hooking dll using the mhook library. In a spezial case the NtOpenFile() fails when a std::wstring is defined as stack var. Defining it on the heap the code is working.
The code is working without problems except when a certain win32 application (lets call it nuisance.exe) tries to open an existing testfile (like c:\temp\anyfile.log) the access fails. Mostly STATUS_INVALID_ACL (0xC0000077) is returned then.
I have reduced my code line by line and finally found that the error happens when in a called function a std::wstring is defined (this example below). The error happens every time an on different OS's
NTSTATUS NtOpenFileApiHook::NtOpenFileHook(PHANDLE FileHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PIO_STATUS_BLOCK IoStatusBlock,
ULONG ShareAccess,
ULONG OpenOptions
)
{
NTSTATUS Status = STATUS_SUCCESS;
// using this function the call will fail
AfterThis_NtOpenFile_WillFail();
// using this function INSTEAD the call will work
AfterThis_NtOpenFile_WillWork();
// calling the real NtOpenFile using a pointer
// nothing was changed hier, the original parameters are passed
Status = RealNtOpenFile(FileHandle, ...);
return Status;
}
int AfterThis_NtOpenFile_WillFail()
{
std::wstring String = L"";
return 0;
}
int AfterThis_NtOpenFile_WillWork()
{
std::wstring * pString = new std::wstring();
pString->assign(L"");
delete pString;
return 0;
}
I have fixed it this way for this call. But I'm afraid that other functions in other circumstainces could fail so I'm looking for the reason and (probably) for a solution.
Nuisance.exe is a C# application with default stacksize callling a win32 dll about which I know nothing.
If Nuisance.exe was a C++ application, I would imagine that it calls NtOpenFile in a way similar to this, allocating one of pointer parameters on overwritten stack:
POBJECT_ATTRIBUTES MakeObjectAttributes()
{
POBJECT_ATTRIBUTES oa = {...};
return &oa; // Pointer to stack variable - UB
}
...
NtOpenFile(..., MakeObjectAttributes(), ...)
STATUS_INVALID_ACL (0xC0000077) error might suggest that SecurityDescriptor within OBJECT_ATTRIBUTES is allocated this way.
Then it matters how much stack is used by AfterThis_NtOpenFile_WillFail, and it is more than AfterThis_NtOpenFile_WillWork, since std::wstring would be larger than just a couple of pointers due to small string optimization.
If the call chain is always the same, the corruption may be deterministic.
I don't know if code equivalent of returning address of temporary is possible in C#. But the DLL may be in C/C++ or similar language that allows dandling pointers.
To prove/disprove the role of stack, try to allocate other data on stack that has std::wstring size. More precise proof could be checking passed pointer to see if they point to stack area that is about to be overwritten.
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 find myself in need of help. Now, I'm not all that unfamiliar with C++, but combining it with ATL provides a whole new level of confusion. Anyways, my problem: I (finally) managed to return an array of objects in my COM method to C# caller. But upon 'testing' (running said function a number of times repeatedly) I recognized a small memory leak.
IDL excerpt:
...
interface IDISControl : IDispatch{
...
[id(12)] HRESULT GetNets([out,retval] VARIANT* nets);
};
Header excerpt:
...
STDMETHOD(GetNets)(VARIANT* nets);
...
Code:
STDMETHODIMP CDISControl::GetNets(VARIANT* nets)
{
SNet *netz;
int32_t num;
int result, i;
result = DIS_GetNetNum(securityHandle, &num);
netz = new SNet[num];
result = DIS_GetNet(securityHandle, netz, num); //getting some data
CComSafeArray<IDispatch*> netArray;
CComObject<CDISNet> *net;
CComVariant *var;
netArray.Create(num, 0);
for (i = 0;i<num;i++){
CComObject<CDISNet>::CreateInstance(&net);
if (net == NULL)
return S_FALSE;
net->AddRef();
net->Convert(netz[i]);
netArray[i] = net;
net->Release();
net = NULL;
}
CComVariant val(netArray.Detach());
val.Detach(nets);
delete [] netz;
netArray.Destroy();
return S_OK;
}
I instantiate CDISNet objects and put some data in them (Convert()). I put them in my safearray and release. As I understand it, the responsibility for destroying them is transferred to safearray. Afterwards, I box the array in a VARIANT so I can fill my [out, retval] parameter. Since it's an out parameter, the responsibility for destruction should be transferred to caller (in my case C#, i.e. its GarbageCollector). I dispose of my dynamic array 'netz' and I destroy safearray wrapper.
So what am I missing? What is left allocated? (This project is really making me appreciate all the comforts of .net).
Help. Please.
EDIT: Further debugging revealed to me that the problem is certainely in my CComObject objects. They aren't being deallocated. If I delete net; in each iteration the array also looses data. I'm unsure as how to rectify that...
EDIT2:
Ok, I poked around this code for a bit, and the leak seems to go away when I comment out variant boxing. The problem is that I borrowed this piece of code from Visual Studio sample on safearrays. So, does anyone have any idea what's up with:
CComVariant val(netArray.Detach());
val.Detach(nets);
...and what to do about it?
Most, if not all, of ATL's wrappers follow COM conventions -- they copy/addref incoming data, as their destructor will destroy/release.
So when you pass your detached SAFEARRAY to CComVariant's constructor, it will make a copy of the SAFEARRAY, which means nobody releases the result from CComSafeArray::Detach.
In cases like this, I always found it easier to forego the wrapper for the return value entirely;
nets->vt = VT_ARRAY | VT_DISPATCH;
nets->parray = netArray.Detach();
The alternative would be to pass your CComSafeArray directly to CComVariant's constructor, without calling Detach, but that would cost you an extra copy. I'd prefer the raw access presented above, as it is most straightforward and cheapest.
As to your first edit, what you're doing with AddRef/Release is fine, if somewhat unnecessary. CComObject::CreateInstance returns an object with reference count 0, so the AddRef will bring it to 1, and then assigning it to the CComSafeArray will bump it to 2, and the following Release back down to 1.
Unless the Convert method does anything with the object's reference count (e.g. QueryInterface itself or pass itself to another COM method), you could skip the AddRef/Release pair, and let Convert execute with refcount == 0. Then adding it to the array would increase it, and it would stay alive until released.
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;
}