how to return BSTR* values as [out, retval] parameter 
Author Message
 how to return BSTR* values as [out, retval] parameter

My question is about the right way to return BSTR values as [out,
retval] parameters.

I am trying to write a ATL component that reads values in the
registry. The actual read call is done in a Win32 DLL that houses the
C++ class & methods that do the same.

In the ATL Component my IDL decl is as below

HRESULT ReadRegistryValue([in]BSTR bstrKeyName, [in]BSTR
bstrValueName, [out, retval]BSTR* bstrValue);
(I pass the key/value pair and expect the value returned in the out,
retval parameter)

And the method call is as below
STDMETHODIMP CRegAccess::ReadRegistryValue(BSTR bstrKeyName, BSTR
bstrValueName, BSTR *bstrValue)
{
        CRegistryHelper regHelper;
        regHelper.ReadRegistryValue(bstrKeyName, bstrValueName, bstrValue);    

Quote:
}

In the Win32 dll, I have the method that reads registry values as
follows:
void ReadRegistryValue(BSTR& bstrSubKeyName, BSTR& bstrValueName,
BSTR* bstrValue)
{....
.....
//In this function's implementation, I assign a value to bstrValue
like this:
*bstrValue = ::SysAllocString(bstrVal)
//this bstrVal has the value returned from the RegQueryValueEx call
.....
....

Quote:
}

I am able to see the right value when i cast into a CString value in
the DLL for test purposes.

But from a test MFC progrm where i call the ATL component's method
like below:

IRegAccessPtr ptrRegAccess;
try
{
        HRESULT hr  =ptrRegAccess.CreateInstance("RegistryAccess.RegAccess");
        CString str=(BSTR)ptrRegAccess->ReadRegistryValue(bstrKeyName,

bstrValueName)

Quote:
}

The str value is a blank...
While debugging, i notice that the result parameter returned is a
pointer to the right value.

Where am I going wrong??

Thanks in advance
AMohan



Mon, 13 Jun 2005 18:16:56 GMT  
 how to return BSTR* values as [out, retval] parameter

Quote:
> My question is about the right way to return BSTR values as [out,
> retval] parameters.

> void ReadRegistryValue(BSTR& bstrSubKeyName, BSTR& bstrValueName,
> BSTR* bstrValue)
> {....
> //In this function's implementation, I assign a value to bstrValue
> like this:
> *bstrValue = ::SysAllocString(bstrVal)
> //this bstrVal has the value returned from the RegQueryValueEx call
> }

The most interesting piece of code is the one you failed to show: how
bstrVal is declared, how it obtains its value.
--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken



Mon, 13 Jun 2005 22:51:18 GMT  
 how to return BSTR* values as [out, retval] parameter
Hi,

Yes, maybe that is where I am going wrong. Here is how I am assigning
the value to bstrVal:
The full code....first open the registry key, and then query for the
data...

long lRet = RegOpenKeyEx(m_hKey, pszKeyName, 0, KEY_ALL_ACCESS,
&m_hKey);
        if (lRet == ERROR_SUCCESS)
        {
                //Thanx to Jeff Richter's AutoBuf class
                CAutoBuf<PTSTR, sizeof(TCHAR)> pszValue;
                pszValue = 1;
                do {
                   lRet = RegQueryValueEx(m_hKey, pszValueName, NULL, NULL,
                          pszValue, pszValue);
                   //now, point the data to the output varaible
                   BSTR bstrVal = (unsigned short*)PBYTE(pszValue);
                   *bstrRegValue = ::SysAllocString(bstrVal);

                } while (lRet == ERROR_MORE_DATA);

I notice in the de{*filter*} that bastVal points to the correct data.
After assignment to *bstrRegValue and coming out of the dll, the data
points to some junk like this: "???????0????"

Thank you
Anil.

Quote:



> > My question is about the right way to return BSTR values as [out,
> > retval] parameters.

> > void ReadRegistryValue(BSTR& bstrSubKeyName, BSTR& bstrValueName,
> > BSTR* bstrValue)
> > {....
> > //In this function's implementation, I assign a value to bstrValue
> > like this:
> > *bstrValue = ::SysAllocString(bstrVal)
> > //this bstrVal has the value returned from the RegQueryValueEx call
> > }

> The most interesting piece of code is the one you failed to show: how
> bstrVal is declared, how it obtains its value.



Fri, 17 Jun 2005 12:23:50 GMT  
 how to return BSTR* values as [out, retval] parameter
   BSTR bstrVal = (unsigned short*)PBYTE(pszValue);
   *bstrRegValue = ::SysAllocString(bstrVal);

This cast is illegal. you have a ANSI string and you make it 'unicode' by
using a cast to unsigned short*???
Use the CA2W() macro to convert to unicode. something like
*bstrRegvalue = ::SysAllocString(CA2W(pszValue));

--

Quote:
> Hi,

> Yes, maybe that is where I am going wrong. Here is how I am assigning
> the value to bstrVal:
> The full code....first open the registry key, and then query for the
> data...

> long lRet = RegOpenKeyEx(m_hKey, pszKeyName, 0, KEY_ALL_ACCESS,
> &m_hKey);
> if (lRet == ERROR_SUCCESS)
> {
> //Thanx to Jeff Richter's AutoBuf class
> CAutoBuf<PTSTR, sizeof(TCHAR)> pszValue;
> pszValue = 1;
> do {
>    lRet = RegQueryValueEx(m_hKey, pszValueName, NULL, NULL,
>   pszValue, pszValue);
>    //now, point the data to the output varaible
>    BSTR bstrVal = (unsigned short*)PBYTE(pszValue);
>    *bstrRegValue = ::SysAllocString(bstrVal);

> } while (lRet == ERROR_MORE_DATA);

> I notice in the de{*filter*} that bastVal points to the correct data.
> After assignment to *bstrRegValue and coming out of the dll, the data
> points to some junk like this: "???????0????"

> Thank you
> Anil.




- Show quoted text -

Quote:


> > > My question is about the right way to return BSTR values as [out,
> > > retval] parameters.

> > > void ReadRegistryValue(BSTR& bstrSubKeyName, BSTR& bstrValueName,
> > > BSTR* bstrValue)
> > > {....
> > > //In this function's implementation, I assign a value to bstrValue
> > > like this:
> > > *bstrValue = ::SysAllocString(bstrVal)
> > > //this bstrVal has the value returned from the RegQueryValueEx call
> > > }

> > The most interesting piece of code is the one you failed to show: how
> > bstrVal is declared, how it obtains its value.



Fri, 17 Jun 2005 16:11:47 GMT  
 how to return BSTR* values as [out, retval] parameter

Quote:
> CAutoBuf<PTSTR, sizeof(TCHAR)> pszValue;
> pszValue = 1;
> do {
>    lRet = RegQueryValueEx(m_hKey, pszValueName, NULL, NULL,
>   pszValue, pszValue);
>    //now, point the data to the output varaible
>    BSTR bstrVal = (unsigned short*)PBYTE(pszValue);
>    *bstrRegValue = ::SysAllocString(bstrVal);

> } while (lRet == ERROR_MORE_DATA);

Besides a problem pointed to by Egbert Nierop (casting an Ansi buffer to
Unicode, instead of converting), you have a memory leak here. You call
SysAllocString in a loop, but you don't have a matching SysFreeString.
Suppose the loop makes 10 iterations. You end up calling SysAllocString
10 times, each time overwriting the previous pointer with new one. You
then return the last allocation as an [out] parameter, so the client is
responsible for calling SysFreeString once. You have 9 allocated BSTRs
that are never going to be freed.

RegQueryValueEx can return the required size of the buffer. Do it like
this:

DWORD dwSize = 0;
RegQueryValueEx(m_hKey, pszValueName, 0, 0, 0, &dwSize);
// Assuming the above call succeeds, size holds the required size of the
buffer
// in bytes, including the terminating NULL for the string
// Attention: dwSize is the size in bytes, not in characters, even if
the value
// is of type REG_SZ and you have Unicode build.

CAutoBuf<PTSTR, sizeof(TCHAR)> pszValue;
pszValue = dwSize/sizeof(TCHAR);
// Not sure whether CAutoBuf expects size in bytes or in characters
// Th above line assumes characters. Drop "/sizeof(TCHAR)" if it wants
bytes

RegQueryValueEx(m_hKey, pszValueName, 0, 0, pszValue, &dwSize);

// CComBSTR constructor takes care of necessary conversion
// and makes SysAllocString call as appropriate
*bstrRegValue = CComBSTR(pszValue).Detach();

--
With best wishes,
    Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken



Fri, 17 Jun 2005 22:48:02 GMT  
 how to return BSTR* values as [out, retval] parameter
That was real stupid of me...not to convert the strings and hoping it would work.
Thanks very much for the help. It now works as expected.

Wish you a very happy new year.

Regards
Anil.

Quote:



> > CAutoBuf<PTSTR, sizeof(TCHAR)> pszValue;
> > pszValue = 1;
> > do {
> >    lRet = RegQueryValueEx(m_hKey, pszValueName, NULL, NULL,
> >   pszValue, pszValue);
> >    //now, point the data to the output varaible
> >    BSTR bstrVal = (unsigned short*)PBYTE(pszValue);
> >    *bstrRegValue = ::SysAllocString(bstrVal);

> > } while (lRet == ERROR_MORE_DATA);

> Besides a problem pointed to by Egbert Nierop (casting an Ansi buffer to
> Unicode, instead of converting), you have a memory leak here. You call
> SysAllocString in a loop, but you don't have a matching SysFreeString.
> Suppose the loop makes 10 iterations. You end up calling SysAllocString
> 10 times, each time overwriting the previous pointer with new one. You
> then return the last allocation as an [out] parameter, so the client is
> responsible for calling SysFreeString once. You have 9 allocated BSTRs
> that are never going to be freed.

> RegQueryValueEx can return the required size of the buffer. Do it like
> this:

> DWORD dwSize = 0;
> RegQueryValueEx(m_hKey, pszValueName, 0, 0, 0, &dwSize);
> // Assuming the above call succeeds, size holds the required size of the
> buffer
> // in bytes, including the terminating NULL for the string
> // Attention: dwSize is the size in bytes, not in characters, even if
> the value
> // is of type REG_SZ and you have Unicode build.

> CAutoBuf<PTSTR, sizeof(TCHAR)> pszValue;
> pszValue = dwSize/sizeof(TCHAR);
> // Not sure whether CAutoBuf expects size in bytes or in characters
> // Th above line assumes characters. Drop "/sizeof(TCHAR)" if it wants
> bytes

> RegQueryValueEx(m_hKey, pszValueName, 0, 0, pszValue, &dwSize);

> // CComBSTR constructor takes care of necessary conversion
> // and makes SysAllocString call as appropriate
> *bstrRegValue = CComBSTR(pszValue).Detach();



Sat, 18 Jun 2005 14:56:39 GMT  
 how to return BSTR* values as [out, retval] parameter
Thanks very much....real dumb me!! Works as expected now.

Wish you a very good year ahead.

Regards
Anil.


Quote:
> BSTR bstrVal = (unsigned short*)PBYTE(pszValue);
>    *bstrRegValue = ::SysAllocString(bstrVal);

> This cast is illegal. you have a ANSI string and you make it 'unicode' by
> using a cast to unsigned short*???
> Use the CA2W() macro to convert to unicode. something like
> *bstrRegvalue = ::SysAllocString(CA2W(pszValue));

> --



Sat, 18 Jun 2005 15:00:35 GMT  
 
 [ 7 post ] 

 Relevant Pages 

1. method parameters..... [out, retval] BSTR *pointer

2. How to return an interface in an [out, retval] VARIANT* parameter

3. How to return a value in a BSTR?

4. SysFreeString called twice / [out, retval] BSTR *

5. How can I return bstr value to client

6. Make length on BSTR return value?

7. Method Output Parameter vs Return Value

8. Generic object as method parameter / return value?

9. function parameters and return values aren't changed by function call

10. Returning[out,retval] interface to VB error

11. function parameters: default value, optional parameter

12. Simple C++ question: Using return values (by value)

 

 
Powered by phpBB® Forum Software