I've this situation:
---------------------------------------------------------------------------
/*
* CH 1 -> [KEY1][KEY2]...[KEYn]
* CH 2 -> [KEY1][KEY2]...[KEYn]
* / \
* CComPtr<IWaveStream>
*/
typedef std::map < std::string, CComPtr<IWaveStream> > t_streams_map;
typedef std::map < short, t_streams_map >
t_ch_streams_map;
STDMETHODIMP CAudioPlayer::CreateStream(BSTR key,
short channel,
IWaveStream** ret_stream)
{
std::string sKey((char*)_bstr_t(key));
CComPtr<IWaveStream> iStream;
HRESULT hr = CComCoClass<CWaveStream>::CreateInstance(&iStream);
if (SUCCEEDED(hr))
{
//Store the object into the map
streams_map_[channel][sKey] = iStream;
if (ret_stream)
iStream->QueryInterface(IID_IWaveStream, reinterpret_cast<void**>
(ret_stream));
}
return rv;
};
//-----------------------------------------------------------------------
STDMETHODIMP CAudioPlayer::GetWaveStreamObj(BSTR key, short channel,
IWaveStream** pVal)
{
if (pVal)
{
//Find the object in the map
t_streams_map::iterator it = streams_map_[channel].find
( std::string((char*)_bstr_t(key)) );
//If I found it, I return it.
if ( it != streams_map_[channel].end() )
return it->second->QueryInterface(IID_IWaveStream,
reinterpret_cast<void**>(pVal));
return S_OK;
}
else
return E_POINTER;
};
//-----------------------------------------------------------------------
void CAudioPlayer::FinalRelease()
{
for (t_ch_streams_map::iterator map_it = streams_map_.begin();
map_it != streams_map_.end();
map_it++)
{
for (t_streams_map::iterator item = (*map_it).second.begin();
item != (*map_it).second.end();
item++)
(*item).second.Release();
}
};
---------------------------------------------------------------------------
In the CWaveStream class I have a member *m_stream (that is a _simple_
pointer to another class). This member is correctly initialized in the
constructor.
When I call CAudioPlayer::GetWaveStreamObj from the client, I get the
object but its *m_stream member is became 0!
Also, when I terminate the application the CAudioPlayer::FinalRelease
() is called but CWaveStream::FinalRelease() is not!
Someone see errors in my code?
Thanks!
Daniele.
I'm afraid I can't help you here. You haven't shown any relevant code. I guess you could place a breakpoint everywhere m_stream is assigned, and find out where it's set to NULL
> Also, when I terminate the application the CAudioPlayer::FinalRelease
> () is called but CWaveStream::FinalRelease() is not!
It's possible for the client to release all references on CAudioPlayer but keep around its references to IWaveStream. There's nothing in your code that would prevent an instance of CWaveStream from outliving that of CAudioPlayer.
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
Hi Igor,
thanks for your time..
Ok, I post the entire code.
This ActiveX is a wrapper around a C++ static library (Namespace
EuroAudioLib).
I replicate the same behaviour of the library creating "same" classes,
so the CWaveStream holds a pointer to a EuroAudioLib::WaveStream
object.
The CAudioPlayer simply holds a collection of streams stored in a
std::map like I wrote in the previous post.
WaveStream.h
-------------
// WaveStream.h : Declaration of the CWaveStream
#pragma once
#include "resource.h" // main symbols
#include "AxAudioLib4_i.h"
#include "_IWaveStreamEvents_CP.h"
#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined
(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#error "Single-threaded COM objects are not properly supported on
Windows CE platform, such as the Windows Mobile platforms that do not
include full DCOM support. Define
_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support
creating single-thread COM object's and allow use of it's single-
threaded COM object implementations. The threading model in your rgs
file was set to 'Free' as that is the only threading model supported
in non DCOM Windows CE platforms."
#endif
class CWaveStream;
/////////////////////////////////////////////////////////////////////////////
// WaveStreamEvents
class WaveStreamEvents : public EuroAudioLib::IWaveStreamEvents
{
public:
WaveStreamEvents(CWaveStream &WaveStreamObj);
void OnStreamStateChanged(EuroAudioLib::IWaveStream* Sender, int
new_state);
void OnStreamDebugMsg(EuroAudioLib::IWaveStream* Sender, std::string
msg);
void OnStreamEnd(EuroAudioLib::IWaveStream* Sender);
private:
CWaveStream& WaveStreamObj_;
};
// CWaveStream
class ATL_NO_VTABLE CWaveStream :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CWaveStream, &CLSID_WaveStream>,
public ISupportErrorInfo,
public IConnectionPointContainerImpl<CWaveStream>,
public CProxy_IWaveStreamEvents<CWaveStream>,
public IDispatchImpl<IWaveStream, &IID_IWaveStream,
&LIBID_AxAudioLib4, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
CWaveStream();
DECLARE_REGISTRY_RESOURCEID(IDR_WAVESTREAM)
BEGIN_COM_MAP(CWaveStream)
COM_INTERFACE_ENTRY(IWaveStream)
//COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(ISupportErrorInfo)
COM_INTERFACE_ENTRY(IConnectionPointContainer)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CWaveStream)
CONNECTION_POINT_ENTRY(__uuidof(_IWaveStreamEvents))
END_CONNECTION_POINT_MAP()
// ISupportsErrorInfo
STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct();
void FinalRelease();
public:
void SetStreamObj(EuroAudioLib::IWaveStream *stream);
STDMETHOD(get_DebugEnabled)(/*[out, retval]*/ VARIANT_BOOL*);
STDMETHOD(put_DebugEnabled)(/*[in]*/ VARIANT_BOOL mode);
STDMETHOD(get_Compression)(/*[out, retval]*/ short*);
STDMETHOD(put_Compression)(/*[in]*/ short compression);
STDMETHOD(get_StreamType)(/*[out, retval]*/ E_STREAM_TYPE*);
//STDMETHOD(LocalIPList(TIpList* ip_list);
STDMETHOD(get_LocalPort)(/*[out, retval]*/ short*);
STDMETHOD(put_LocalPort)(/*[in]*/ short port);
STDMETHOD(get_RemotePort)(/*[out, retval]*/ short*);
STDMETHOD(put_RemotePort)(/*[in]*/ short port);
STDMETHOD(get_RxTimerIterval)(/*[out, retval]*/ short*);
STDMETHOD(put_RxTimerIterval)(/*[in]*/ short value);
STDMETHOD(get_TxIP)(/*[out, retval]*/ BSTR*);
STDMETHOD(put_TxIP)(/*[in]*/ BSTR ip_address);
STDMETHOD(get_RxIP)(/*[out, retval]*/ BSTR*);
STDMETHOD(put_RxIP)(/*[in]*/ BSTR ip_address);
STDMETHOD(get_EnableRTX)(/*[out, retval]*/ VARIANT_BOOL*);
STDMETHOD(put_EnableRTX)(/*[in]*/ VARIANT_BOOL value);
STDMETHOD(get_StreamState)(/*[out, retval]*/ E_STREAM_STATE*);
STDMETHOD(get_Key)(/*[out, retval]*/ BSTR*);
STDMETHOD(GetLastError)(/*[out, retval]*/ short*);
STDMETHOD(GetLastErrorStr)(/*[out, retval]*/ BSTR*);
STDMETHOD(Bind)(/*[in, defaultvalue(0)]*/ short local_port,
/*[out, retval]*/ E_AUDIOLIB_RET_VAL *pVal);
STDMETHOD(SendRTPPacket)(/*[in]*/ long lpData,
/*[in]*/ short len,
/*[in, defaultvalue(0)]*/ short pt,
/*[in, defaultvalue(0)]*/ VARIANT_BOOL
mark,
/*[in, defaultvalue(0)]*/ long
timestampinc,
/*[out, retval]*/ short*);
STDMETHOD(SendRTPPacketEx)(/*[in]*/ long lpData,
/*[in]*/ short len,
/*[in, defaultvalue(0)]*/ short
hdrextID,
/*[in, defaultvalue(0)]*/ long
lphdrextdata,
/*[in, defaultvalue(0)]*/ short
numhdrextwords,
/*[in, defaultvalue(0)]*/ short pt,
/*[in, defaultvalue(0)]*/ VARIANT_BOOL
mark,
/*[in, defaultvalue(0)]*/ long
timestampinc,
/*[out, retval]*/ short*);
private:
EuroAudioLib::IWaveStream *stream_;
WaveStreamEvents stream_ev_;
};
// This object is 'noncreatable' so we change the Object entry
// so the object is noncreatable but the control is registered
//OBJECT_ENTRY_AUTO(__uuidof(WaveStream), CWaveStream)
OBJECT_ENTRY_NON_CREATEABLE_EX_AUTO(__uuidof(WaveStream), CWaveStream)
---------------------------
CWaveStream.cpp
---------------------------
// WaveStream.cpp : Implementation of CWaveStream
#include "stdafx.h"
#include "WaveStream.h"
//------------------------------------------------------------------------------
// WaveStreamEvents Implementation
//------------------------------------------------------------------------------
WaveStreamEvents::WaveStreamEvents(CWaveStream &WaveStreamObj) :
WaveStreamObj_(WaveStreamObj)
{
};
//------------------------------------------------------------------------------
void WaveStreamEvents::OnStreamStateChanged(EuroAudioLib::IWaveStream*
Sender, int new_state)
{
WaveStreamObj_.Fire_OnStreamStateChanged(&WaveStreamObj_,
new_state);
};
//------------------------------------------------------------------------------
void WaveStreamEvents::OnStreamEnd(EuroAudioLib::IWaveStream* Sender)
{
WaveStreamObj_.Fire_OnStreamEnd(&WaveStreamObj_);
};
//------------------------------------------------------------------------------
void WaveStreamEvents::OnStreamDebugMsg(EuroAudioLib::IWaveStream*
Sender, std::string msg)
{
_bstr_t b_msg(msg.c_str());
WaveStreamObj_.Fire_OnStreamDebugMsg( &WaveStreamObj_, b_msg.copy
() );
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// CWaveStream
STDMETHODIMP CWaveStream::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IWaveStream
};
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
//------------------------------------------------------------------------------
HRESULT CWaveStream::FinalConstruct()
{
return S_OK;
}
//------------------------------------------------------------------------------
void CWaveStream::FinalRelease()
{
}
//------------------------------------------------------------------------------
CWaveStream::CWaveStream() : stream_ev_(*this), stream_(NULL)
{
};
//------------------------------------------------------------------------------
void CWaveStream::SetStreamObj(EuroAudioLib::IWaveStream *stream)
{
stream_ = stream;
//I register my stream_ev_ member like event handler
stream_->AttachEventHandler(&stream_ev_);
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::get_DebugEnabled(VARIANT_BOOL* pVal)
{
if (stream_) *pVal = stream_->getDebugMode();
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::put_DebugEnabled(VARIANT_BOOL mode)
{
if (stream_) stream_->setDebugMode(mode);
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::get_Compression(short* pVal)
{
if (stream_) *pVal = stream_->getCompression();
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::put_Compression(short compression)
{
if (stream_) stream_->setCompression(compression);
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::get_StreamType( E_STREAM_TYPE* pVal)
{
if (stream_) *pVal = static_cast<E_STREAM_TYPE>(stream_-
>getStreamType());
return S_OK;
};
//------------------------------------------------------------------------------
//STDMETHODIMP CWaveStream::LocalIPList(TIpList* ip_list)
//{
//};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::get_LocalPort(short* pVal)
{
if (stream_) *pVal = stream_->getLocalPort();
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::put_LocalPort(short port)
{
if (stream_) stream_->setLocalPort(port);
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::get_RemotePort(short* pVal)
{
if (stream_) *pVal = stream_->getRemotePort();
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::put_RemotePort(short port)
{
if (stream_) stream_->setRemotePort(port);
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::get_RxTimerIterval(short* pVal)
{
if (stream_) *pVal = stream_->getRxTimerIterval();
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::put_RxTimerIterval(short value)
{
if (stream_) stream_->setRxTimerIterval(value);
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::get_TxIP(BSTR* pVal)
{
if (stream_) {
_bstr_t* sIP = new _bstr_t( stream_->getTxIP().c_str() );
*pVal = sIP->copy();
}
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::put_TxIP(BSTR ip_address)
{
if (stream_) {
std::string sIP((char*)_bstr_t(ip_address));
stream_->setTxIP(sIP);
}
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::get_RxIP(BSTR* pVal)
{
if (stream_) {
_bstr_t* sIP = new _bstr_t( stream_->getTxIP().c_str() );
*pVal = sIP->copy();
}
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::put_RxIP(BSTR ip_address)
{
if (stream_) {
std::string sIP((char*)_bstr_t(ip_address));
stream_->setRxIP(sIP);
}
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::get_EnableRTX(VARIANT_BOOL* pVal)
{
if (stream_) *pVal = stream_->getEnableRTX();
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::put_EnableRTX(VARIANT_BOOL value)
{
if (stream_) stream_->setEnableRTX(value);
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::get_StreamState(E_STREAM_STATE* pVal)
{
if (stream_) *pVal = static_cast<E_STREAM_STATE>(stream_-
>getStreamState());
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::get_Key(BSTR* pVal)
{
if (stream_) {
_bstr_t* bstr = new _bstr_t(stream_->Key().c_str());
*pVal = bstr->copy();
}
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::GetLastError(short* pVal)
{
if (stream_) *pVal = stream_->GetLastError();
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::GetLastErrorStr(BSTR* pVal)
{
if (stream_) {
_bstr_t* bstr = new _bstr_t(stream_->GetLastErrorStr().c_str());
*pVal = bstr->copy();
}
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::Bind(short local_port, E_AUDIOLIB_RET_VAL
*pVal)
{
if (stream_) *pVal = static_cast<E_AUDIOLIB_RET_VAL>(stream_->Bind
(local_port));
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::SendRTPPacket(long lpData,
short len,
short pt,
VARIANT_BOOL mark,
long timestampinc,
short* pVal)
{
if (stream_) *pVal = stream_->SendRTPPacket((const void*)lpData,
len, pt, mark, timestampinc);
return S_OK;
};
//------------------------------------------------------------------------------
STDMETHODIMP CWaveStream::SendRTPPacketEx(long lpData,
short len,
short hdrextID,
long lphdrextdata,
short
numhdrextwords,
short pt,
VARIANT_BOOL mark,
long timestampinc,
short* pVal)
{
return S_FALSE;
};
//------------------------------------------------------------------------------
The VB6 client code is simply a test:
Dim p As AudioPlayer
Private Sub Form_Load()
Dim ws As WaveStream
PrintLog "CREATE A WAVE STREAM1"
Set ws = p.CreateStream("STREAM1")
PrintLog "ActiveStream.Key = " & p.GetActiveStream.Key
PrintLog "RxIP = " & ws.RxIP
PrintLog "TxIP = " & ws.TxIP
PrintLog "CREATE A WAVE STREAM2"
Set ws = p.CreateStream("STREAM2")
PrintLog "ActiveStream.Key = " & p.GetActiveStream.Key
PrintLog "DELETE STREAM 2": p.DeleteStream "STREAM2"
PrintLog "ActiveStream.Key = " & p.GetActiveStream.Key
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set p = Nothing
End Sub
I hope someone can find my error...
Thanks,
Daniele.
The code you show never calls SetStreamObj, so as far as I can tell, steam_ would always be NULL. I don't see any place where an instance of EuroAudioLib::IWaveStream is created.
> void WaveStreamEvents::OnStreamDebugMsg(EuroAudioLib::IWaveStream*
> Sender, std::string msg)
> {
> _bstr_t b_msg(msg.c_str());
> WaveStreamObj_.Fire_OnStreamDebugMsg( &WaveStreamObj_, b_msg.copy
> () );
I'm pretty sure you are leaking a BSTR here.
> STDMETHODIMP CWaveStream::get_TxIP(BSTR* pVal)
> {
> if (stream_) {
> _bstr_t* sIP = new _bstr_t( stream_->getTxIP().c_str() );
> *pVal = sIP->copy();
And here you are leaking both a heap-allocated _bstr_t object and the BSTR it wraps.
> STDMETHODIMP CWaveStream::get_RxIP(BSTR* pVal)
> {
> if (stream_) {
> _bstr_t* sIP = new _bstr_t( stream_->getTxIP().c_str() );
> *pVal = sIP->copy();
Same here, and everywhere you have a getter for a BSTR property.
Hi Igor,
I changed the CreateStream method and now it works:
STDMETHODIMP CAudioPlayer::CreateStream(BSTR key,
short channel,
IWaveStream** ret_stream)
{
std::string sKey((char*)_bstr_t(key));
CComPtr<IWaveStream> iStream;
CWaveStream* pStream;
HRESULT hr = CComCoClass<CWaveStream>::CreateInstance(&iStream);
if (SUCCEEDED(hr))
{
//Store the object into the map
streams_map_[channel][sKey] = iStream;
pStream = (CWaveStream*)iStream.p;
pStream->SetStreamObj( device->CreateStream(sKey, channel) );
if (ret_stream)
iStream->QueryInterface(IID_IWaveStream, reinterpret_cast<void**>
(ret_stream));
}
return rv;
};
>
> > void WaveStreamEvents::OnStreamDebugMsg(EuroAudioLib::IWaveStream*
> > Sender, std::string msg)
> > {
> > _bstr_t b_msg(msg.c_str());
> > WaveStreamObj_.Fire_OnStreamDebugMsg( &WaveStreamObj_, b_msg.copy
> > () );
>
> I'm pretty sure you are leaking a BSTR here.
Maybe I have to use .Detach():
WaveStreamObj_.Fire_OnStreamDebugMsg(&WaveStreamObj_, b_msg.Detach())
>
> > STDMETHODIMP CWaveStream::get_TxIP(BSTR* pVal)
> > {
> > if (stream_) {
> > _bstr_t* sIP = new _bstr_t( stream_->getTxIP().c_str() );
> > *pVal = sIP->copy();
>
> And here you are leaking both a heap-allocated _bstr_t object and the BSTR it wraps.
Is this better?
if (pVal) {
_bstr_t* bstr = new _bstr_t( device_->getFileName(channel).c_str
() );
*pVal = bstr->Detach();
delete bstr;
}
Thanks a lot for your suggestions!
Daniele.
typedef std::map < std::string, CAdapt<CComPtr<IWaveStream> > >
t_streams_map;
Brian
Just do
WaveStreamObj_.Fire_OnStreamDebugMsg(&WaveStreamObj_, b_msg)
>>> STDMETHODIMP CWaveStream::get_TxIP(BSTR* pVal)
>>> {
>>> if (stream_) {
>>> _bstr_t* sIP = new _bstr_t( stream_->getTxIP().c_str() );
>>> *pVal = sIP->copy();
>>
>> And here you are leaking both a heap-allocated _bstr_t object and
>> the BSTR it wraps.
>
> Is this better?
>
> if (pVal) {
> _bstr_t* bstr = new _bstr_t( device_->getFileName(channel).c_str
> () );
> *pVal = bstr->Detach();
> delete bstr;
> }
Yes, though it's not clear why you create _bstr_t instance on the heap. Why not just
*pVal = _bstr_t(...).Detach();
In the beginning I supposed that, since I have to return a pointer to
BSTR, I had to create the string on the heap.
If I create the BSTR on the stack, when I return, the BSTR* pVal what
point to?
Maybe I need to do:
if (pVal) {
_bstr_t bstr( ..... );
*pVal = bstr->copy();
}
Thanks,
Daniele.
"Barzo" <dba...@gmail.com> ha scritto nel messaggio
news:b99be3d8-92cc-4857...@c3g2000yqd.googlegroups.com...
>> Yes, though it's not clear why you create _bstr_t instance on the heap.
>> Why not just
>>
>> *pVal = _bstr_t(...).Detach();
>
> In the beginning I supposed that, since I have to return a pointer to
> BSTR, I had to create the string on the heap.
BSTR's are always created using SysAllocString (or similar APIs like
SysAllocStringLen).
(I think that under the hood these APIs call CoTaskMemAlloc, but I'm not
sure...)
_bstr_t (or CComBSTR) are just C++ *wrapper* classes that help manage BSTR's
using RAII and in a more object-oriented way than the pure C APIs like
SysAllocString, SysFreeString, etc.
Note that BSTR - from the point of view of the C/C++ type system - is just
an 'unsigned short *'
Giovanni
"Barzo" <dba...@gmail.com> ha scritto nel messaggio
news:b99be3d8-92cc-4857...@c3g2000yqd.googlegroups.com...
> If I create the BSTR on the stack, when I return, the BSTR* pVal what
> point to?
BSTR is just an 'unsigned short *' from C/C++ type system point of view.
So, if you "create the BSTR on the stack", you actually create a 'unsigned
short *' (i.e. a pointer) on the stack.
I mean, if you write:
BSTR bstrVal;
this is equivalent as writing:
unsigned short * bstrVal;
So, a pointer identified by 'bstrVal' is created on the stack. The value of
the pointer is undefined.
The 'BSTR *pVal' in your case is a pointer to a BSTR, i.e. it is a pointer
to a pointer (a double pointer, something similar to the second argument of
IUnknown::QueryInterface).
BSTR's are created using functions like SysAllocString or similar (wrapper
classes like CComBSTR or _bstr_t call those C functions).
If you have:
_bstr_t bstrWrapper = L"Something...";
this creates a *wrapper* to a BSTR. The wrapper is 'bstrWrapper', and it
allocates the BSTR using something like SysAllocString.
If you write:
BSTR bstr = bstrWrapper.Detach();
the wrapper detaches (i.e. releases) the BSTR it created above (i.e. the
wrapper is no more responsible for managing the BSTR created above).
The BSTR (i.e. an unsigned short *) returned by Detach() is assigned to
'bstr' variable (this variable, which is a pointer, is created on the
stack).
When you write:
// BSTR * pVal
*pVal = bstr;
You are storing the value of the pointer 'bstr' into memory pointed by pVal.
In this way, you can return BSTR's to some calling routine (the caller
passes a pointer to a BSTR, i.e. a BSTR*)
If you want to read interesting information on BSTR semantics, I would
suggest you this post:
"Eric's Complete Guide To BSTR Semantics"
http://blogs.msdn.com/ericlippert/archive/2003/09/12/52976.aspx
> Maybe I need to do:
>
> if (pVal) {
> _bstr_t bstr( ..... );
> *pVal = bstr->copy();
> }
This won't compile.
In fact, 'bstr' is of type '_bstr_t', so you can't use operator-> on 'bstr'.
You may do:
*pVal = bstr.copy();
but in this case you duplicate the BSTR (i.e. you have a BSTR created using
the '_bstr_t' wrapper, and a deep-copy of this BSTR, passed to the caller
using the 'pVal' pointer).
Calling _bstr_t::Detach as Igor suggested is just fine, and is more
efficient than _bstr_t::copy.
In fact, copy() performs a deep copy of the wrapped BSTR (i.e. it allocates
a new BSTR and copies the content from old string to newly allocated one);
instead, Detach() method just moves a pointer (BSTR, i.e. unsigned short *).
Giovanni
Thanks a lot to all for yours explanations and for the time spent for
me!!!
You're been very very clear!
Daniele.