CComBSTR issues

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?
forloopAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

freshmeatCommented:
ha, i am also headache about the "BSTR" string's operation
any experts can help us?
0
mikeblasCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
mikeblasCommented:

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
Get your problem seen by more experts

Be seen. Boost your question’s priority for more expert views and faster solutions

forloopAuthor Commented:
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
forloopAuthor Commented:
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
forloopAuthor Commented:
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
mikeblasCommented:
> 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
forloopAuthor Commented:
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
mikeblasCommented:
> 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
forloopAuthor Commented:
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
mikeblasCommented:
> 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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.