?
Solved

CComBSTR issues

Posted on 1999-12-23
11
Medium Priority
?
639 Views
Last Modified: 2013-12-03
I've got a pair of CComBSTR's and I'd like to character by character copying, but when I do it the way I would with regular arrays the resulting variable is garbage. Here's an example:

int i;
CComBSTR one, two;
for(i=0;i<one.Length();i++)
     two+=one[i];

I've also tried: two[k]=one[i];

The reason for this is I need to do some string substitutions from one string to the other. The append operator and function of CComBSTR doesn't seem to want cooperate with me. I've tried:

two+=_T("Hello");

and when I print the variable I get a weird character following Hello (a box).

Can anyone help me out with a couple of quick eamples of how this thing works?
0
Comment
Question by:forloop
  • 5
  • 5
11 Comments
 
LVL 2

Expert Comment

by:freshmeat
ID: 2304600
ha, i am also headache about the "BSTR" string's operation
any experts can help us?
0
 
LVL 11

Accepted Solution

by:
mikeblas earned 200 total points
ID: 2304783
The reason this doesn't work is pretty simple, if you understand C++: CComBSTR doesn't have an operator[].

When you try to invoke it, you actually implicitly cast the CComBSTR object to a BSTR. Then, you index the given character of the string. That much works: the result is an unsigned short, which is the type of character that appears in a BSTR.

But there's no CComBSTR constructor that takes a single unsigned short, and there's no CComBSTR::operator+= that takes a single unsigned short, either. So, the compiler does what the language rules dictate it must: it tries to find an appropriate constructor.

It turns out the most appropriate constructor is CComBSTR::CComBSTR(int nLength), which creates an unintialized BSTR of the given length.

In this example:

   CComBSTR bstrFoo("Hockey");
   CComBSTR bstrBaz;
 
   unsigned int n;
   for (n = 0; n < bstrFoo.Length(); n++)
   {
      bstrBaz += bstrFoo[n];
   }

the first time thru the loop, you end up creating an uninitialized BSTR which is 72 characters long. Why 72? Because 'H' is the first character for bstrFoo and 'H' == 72.

You _could_ rewrite the loop to create a single-character BSTR, then concatenate that single-character BSTR to the result string.  Like this:

   unsigned int n;
   for (n = 0; n < bstr1.Length(); n++)
   {
      OLECHAR szTemp[2];
      szTemp[1] = 0;
      szTemp[0] = bstr1[n];
      bstr2 += szTemp;
   }

But that's lousy, because you're really churning memory by reallocating everything over and over again. The constructor allocates a new, temporary BSTR. Then, you allocate a slightly longer space for bstr2, copy its existing data over, and then add the new character. Then, you destroy the old BSTR and the temporary, too.

That's really expensive!

If you want to do character-by-character substitution, I think your best bet would be to forego CComBSTR and do it directly on a BSTR--at least, on the m_str that CComBSTR owns.

When I use the += operator with a string constant as the right-hand operand, as you show, I don't have a problem. Can you provide a specific minmal example that repros the problem, I'd be happy to look.

..B ekiM


0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2304790

Er, I meant to edit that:

The reason this doesn't work is pretty simple, if you understand C++: CComBSTR doesn't have any of the operators you're using; there's more missing than just operator[]. I _guess_ this a bug in CComBSTR, but it seems like you're on a slippery slope. If the class had a constructor that took a single OLECHAR, then your code would work. But would be really inefficient for all the reallocation and churn issues that I mentioned in my text.

And, to be more explicitlt, the best way for you write your code would be to predict the size of the new string after all your replacements are done and copy into a new, unallocated BSTR.

So, for example, if you want to change front slashes to backslashes, you know you would be able to do it in exactly the same length.

    CComBSTR bstrInput("from \\ to \\");

    unsigned int nLength = bstrInput.Length();
    CComBSTR bstrOutput(nLength);

    int n;
    for (n = 0; n < nLength; n++)
    {
       if (bstrInput[n] == '\\')
          bstrOutput[n] = '/';
       else
          bstrOutput[n] = bstrInput[n];
    }


If you do more advanced substitution, then the new length won't be so easily predictable. But no matter how much work you do to predict the new length, it'll be better than reallocating and copying for each character.

..B ekiM
0
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 

Author Comment

by:forloop
ID: 2311035
Thanks for the help. I'm still having the trailing character after I do an append (.Append or +=).. So, I tried this to try and solve the problem (both temp and body are CComBSTR's):

temp = pRS->GetCollect("Name").bstrVal;
body.Append(temp.m_str,temp2.Length());

I get the same result. I tried adding a -1 after Length() and the result was interesting..

as shown: "whateveru"
with -1:  "whateveu"

I can't get rid of this trailing character.. even if I set the length to 1 I get 2 characters. This happens with the bstrVal and and something simple like:

body+=_T("Hello"); // yields "Helloo"
0
 

Author Comment

by:forloop
ID: 2311070
Thanks for the help. I'm still having the trailing character after I do an append (.Append or +=).. So, I tried this to try and solve the problem (both temp and body are CComBSTR's):

temp = pRS->GetCollect("Name").bstrVal;
body.Append(temp.m_str,temp2.Length());

I get the same result. I tried adding a -1 after Length() and the result was interesting..

as shown: "whateveru"
with -1:  "whateveu"

I can't get rid of this trailing character.. even if I set the length to 1 I get 2 characters. This happens with the bstrVal and and something simple like:

body+=_T("Hello"); // yields "Helloo"
0
 

Author Comment

by:forloop
ID: 2313882
Thanks for the help. I'm still having the trailing character after I do an append (.Append or +=).. So, I tried this to try and solve the problem (both temp and body are CComBSTR's):

temp = pRS->GetCollect("Name").bstrVal;
body.Append(temp.m_str,temp2.Length());

I get the same result. I tried adding a -1 after Length() and the result was interesting..

as shown: "whateveru"
with -1:  "whateveu"

I can't get rid of this trailing character.. even if I set the length to 1 I get 2 characters. This happens with the bstrVal and and something simple like:

body+=_T("Hello"); // yields "Helloo"
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2314942
> I can't get rid of this trailing character..

I can't make the extra trailing character happen.  Please provide a minimal case that reproduces the problem. Remember to describe your environment fully.

..B ekiM
0
 

Author Comment

by:forloop
ID: 2315518
Ok.. I'm compiling on NT 4.0 Server, Visual C++ 6.0. It's an ATL, NT Service and the active config is Win32 Debug. In the code I'm open a database using ADO (via #import) and I'm reading from fields that are all varchars in SQL. Beyond that, I've got a statment:

CComBSTR body, temp;

some the database code and the code above. This odd extra character is really wierd.. I tried this yesturday:

body+=_T("Hello");
body[body.Length()] = 32;

and variations on the length and I got:

Hell o, Hel oo, He loo, etc

and the trailing character remains every time. It amazes me that good support for the [] operator as well as many other useful string operations aren't available using BSTR's.
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2321332
> some the database code and the code above.

That's not specific enough.  I don't know what pRS is, or what GetCollect() does, or what datatype bstrVal is.

For me to figure out what's wrong, I need to see a complete reproducable case--preferably, one that's a small as possible.

..B ekiM
0
 

Author Comment

by:forloop
ID: 2322048
If you've ever worked with ADO you should know those things.. Open up OLEView on ADO and check the interfaces if you need to. pRS is a recordset interface, GetCollect is a Method for that interface and bstrVal is a variant type because GetCollect returns a variant that has the fields value.

I don't know what to tell you beyond sending you the whole project file. It's just some simple ADO code and the stuff mentioned above.
0
 
LVL 11

Expert Comment

by:mikeblas
ID: 2326423
> If you've ever worked with ADO you should know those things.

I maintained MFC's ADO classes for two years. But that work hasn't built in me the psionic insight to know what your variable names mean.

Your original question said you had trouble with a plain BSTR:

   CComBSTR two;
   two+=_T("Hello");

I can't reproduce the problem using that code.

Please provide a complete repro case. You don't need to provide your whole project--just a function which shows all the declarations you need will suffice.

If I can't reproduce the problem, I can't offer any advice.

..B ekiM
0

Featured Post

Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article shows a few slightly more advanced techniques for Windows 7 gadget programming, including how to save and restore user settings for your gadget and how to populate the "details" panel that is displayed in the Windows 7 gadget gallery.  …
What my article will show is if you ever had to do processing to a listbox without being able to just select all the items in it. My software Visual Studio 2008 crystal report v11 My issue was I wanted to add crystal report to a form and show…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Planning to migrate your EDB file(s) to a new or an existing Outlook PST file? This video will guide you how to convert EDB file(s) to PST. Besides this, it also describes, how one can easily search any item(s) from multiple folders or mailboxes…
Suggested Courses

600 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question