I have to control a measurement application using COM. I'm not really
a COM specialist, so I'm amazed that most parts working perfectly ;-)
But a little detail I find suspect.
The COM interface has a function for loading the setup file
void FileOpen (BSTR FAR* pbstrFileName);
If I do it like (1) then it works:
(1)
BSTR newFile = SysAllocString (_T("Setup.qcc"));
mSaunders250B->FileOpen (&newFile);
SysFreeString (newFile);
If I do it like (2) then it does not work:
(2)
_bstr_t newFile = _T("Setup.qcc");
mSaunders250B->FileOpen (newFile.GetAddress ());
Of course I do it like (1), but after reading and (maybe wrong)
understanding, (2) should work also.
Someone out there who can bring light into the darkness?
Best regards
Walter Eicher
Remark 0: not MFC!
Well... FileOpen seems bad per IDL rules (is this from *.idl, BTW,
or...?). That should be HRESULT FileOpen([in] BSTR FileName); in IDL
and HRESULT FileOpen(BSTR FileName) in *.h. (there's more detail in
there, but it's not relevant). This is because:
1. All COM methods should return HRESULT. If not, e.g. you will never
be able to marshal your interface, but there are probably other
issues.
2. Conceptually speaking, you should have BSTR, not BSTR* there,
because it's an input (or at least that's my guess). You should also
mark it as [in] then. On the client side, you should create a BSTR and
pass it (like in (1), but without "&"). In your server, you just use
it. If you need to keep it, you must make a copy (e.g. CString member;
member = FileName; works)
In general, it looks you should read more upon IDL and COM [in, out,
retval] rules with regard to memory management (I just caught this: ms-
help://MS.VSCC.v90/MS.MSDNQTR.v90.en/rpc/rpc/directional_parameter_attributes.htm).
On Aug 21, 12:26 pm, Walter Eicher
<walter.eic...@nospam.microcrystal.ch> wrote:
>
> If I do it like (1) then it works:
>
> (1)
> BSTR newFile = SysAllocString (_T("Setup.qcc"));
> mSaunders250B->FileOpen (&newFile);
> SysFreeString (newFile);
>
> If I do it like (2) then it does not work:
>
> (2)
> _bstr_t newFile = _T("Setup.qcc");
> mSaunders250B->FileOpen (newFile.GetAddress ());
>
At the first glance, both should work. How does it "not work"?
What are you doing inside FileOpen? If you do *pbstrFileName = NULL,
that may be bad. Also, are you using #import, or are you including
MIDL-generated *.h?
HTH,
Goran.
On Fri, 21 Aug 2009 03:53:11 -0700 (PDT), Goran
<goran...@gmail.com> wrote:
>On Aug 21, 12:26�pm, Walter Eicher
><walter.eic...@nospam.microcrystal.ch> wrote:
>> Hello all,
>>
>> I have to control a measurement application using COM. I'm not really
>> a COM specialist, so I'm amazed that most parts working perfectly ;-)
>>
>> But a little detail I find suspect.
>>
>> The COM interface has a function for loading the setup file
>>
>> � void FileOpen (BSTR FAR* pbstrFileName);
>
>Remark 0: not MFC!
Dont understand this!
I created the interface class with the wizard "MFC Class from TypeLib"
using the 250B.tlb bought from Saunders.
>Well... FileOpen seems bad per IDL rules (is this from *.idl, BTW,
>or...?). That should be HRESULT FileOpen([in] BSTR FileName); in IDL
>and HRESULT FileOpen(BSTR FileName) in *.h. (there's more detail in
>there, but it's not relevant). This is because:
>At the first glance, both should work. How does it "not work"?
It does not load the setup file specified.
Best regards
Walter
Remark 0 meant: you ask much of an MFC question, or at least no
connection with MFC was visible from you first post (there is one if
you used MFC wizard, which you just said now).
Otherwise, I don't know. "it does not load file" is way to far from
the cause for said cause guess anything.
I don't know what would cause the wizard to use BSTR instead of
LPCTSTR (perhaps the use of BSTR __*__?), and that is strange. Perhaps
if you show *.idl of the *.tlb, using OleView?
It is also a bit unfortunate that MFC wizard-generated code basically
forces you to use non-MFC code (to get to an BSTR), but hey.
Goran.
On Fri, 21 Aug 2009 05:12:14 -0700 (PDT), Goran
<goran...@gmail.com> wrote:
>Remark 0 meant: you ask much of an MFC question, or at least no
>connection with MFC was visible from you first post (there is one if
>you used MFC wizard, which you just said now).
>
>Otherwise, I don't know. "it does not load file" is way to far from
>the cause for said cause guess anything.
>
>I don't know what would cause the wizard to use BSTR instead of
>LPCTSTR (perhaps the use of BSTR __*__?), and that is strange. Perhaps
>if you show *.idl of the *.tlb, using OleView?
>
>It is also a bit unfortunate that MFC wizard-generated code basically
>forces you to use non-MFC code (to get to an BSTR), but hey.
Thanks for being with me ;-)
I think I found the cause why the _btsr_t version not works.
I stepped into the function FileOpen and the first hit was
inline BSTR* _bstr_t::GetAddress ()
{
// here m_Data::m_wstr holds "Setup.qcc"
Attach (0);
// here mData::m_wstr holds 0x00000<BadPtr>
return &m_Data->GetWString();
}
FileOpen is then called with a NULL pointer as BSTR*
I dont know what for GetAddress is, but it seems its not for constant
strings.
Best regards
Walter
>Hello all,
>
>I have to control a measurement application using COM. I'm not really
>a COM specialist, so I'm amazed that most parts working perfectly ;-)
>
>But a little detail I find suspect.
>
>The COM interface has a function for loading the setup file
>
> void FileOpen (BSTR FAR* pbstrFileName);
****
Do not use the word FAR in any declaration. It is syntactic gibberish, left over from old
Win16 interfaces and Microsoft has failed to remove it from all definitions, leaving it
around to confuse people and generate cruft like the above declaration. FAR is defined as
#define FAR
and as such, means that any use of it is meaningless noise.
The correct definition is
void FileOpen(BSTR * pbstrFileName);
****
>
>If I do it like (1) then it works:
>
>(1)
> BSTR newFile = SysAllocString (_T("Setup.qcc"));
****
The use of _T() in SysAllocString is also incorrect, because there is no case of
SysAllocStringA/SysAllocStringW. The documentation for SysAllocString *clearly* states
"The sz parameter must be a Unicode string in 32-bit applications"
_T() does not conform to this requirement, except by accident.
****
> mSaunders250B->FileOpen (&newFile);
> SysFreeString (newFile);
>
>If I do it like (2) then it does not work:
****
Please define "does not work". This description is without meaning. Do you mean "It
fails to compile" or "it fails to link" or "it fails to run correctly and returns me an
HRESULT of <value here>" or "it fails to run correctly and causes an exception" or "it
fails to run correctly and <your description of observed value here>"? How in the world
are we supposed to guess what you mean by "does not work"????
****
>
>(2)
> _bstr_t newFile = _T("Setup.qcc");
> mSaunders250B->FileOpen (newFile.GetAddress ());
****
Note that the _bstr_t assignment using _T() works even in 8-bit apps because there is an
overloaded = operator for _bstr_t which accepts an 8-bit string.
However, the Microsoft documentation is not really clear on the difference between
GetAddress and GetBSTR; I suspect you should try it using GetBSTR. I have read the code
of _bstr_t::GetAddress and _bstr_t::GetBSTR, and although the documentation does not state
it, the comments in the code say that GetAddress is used when the parameter is an "out"
parameter. It appears that GetAddress sets the contents to NULL, although it is a bit
hard to track down; the Attach(0) in that code is suspiciously passing a NULL pointer to a
chain of other functions. So it probably clears out the string.
I am adding these to my list of documentation failures.
joe
****
>
>Of course I do it like (1), but after reading and (maybe wrong)
>understanding, (2) should work also.
>
>Someone out there who can bring light into the darkness?
>
>Best regards
>Walter Eicher
>
>
>
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
On Fri, 21 Aug 2009 15:43:47 +0200, Walter Eicher <walter...@nospam.microcrystal.ch>
wrote:
>Hi Goran,
Haha, true, but in all likelihood it's wizard-generated. MIDL output
is quite full of this noise, too. Not Walter's fault.
BTW, everyone, I just looked at the use-case for _bstr_t::GetAddress
here: http://msdn.microsoft.com/en-us/library/34ywz0se(VS.80).aspx.
Well, that's one piece of clear design right there (not). It goes like
this:
bstr= SysAllocString(OLESTR("Yet another string"));
*bstrWrapper.GetAddress() = bstr;
Bwahahahahaaaaa...
So the purpose is to "assign" SysAlloc-ed BSTR to an existing _bstr_t,
without copying a BSTR. Obviously, to avoid leaks, _bstr_t is cleared
prior to emitting BSTR* of GetAddress. And it gets worse: since
_bstr_t is refcounted, this innocuous "Get" effectively changes the
value of all _bstr_t instances sharing underlying data.
I mean, seriously... Who, in the name of God, could even think this is
clear, or reasonable, is beyond me. And remark in GetAddress is
seriously useless: "GetAddress affects all _bstr_t objects that share
a BSTR. More than one _bstr_t can share a BSTR through the use of the
copy constructor and and operator=." Erm... It's a "Get". Why the hell
does it affect anything!? Is the absence of "const" qualifier supposed
to be a hint?
You know what?
_bstr_t::ReplaceUnderlyingBSTROfAllInstancesSharingUnderlyingData(BSTR
in)
would have been more clear.
These MS people are funny.
In any case, the mystery is cleared: GetAdress cleared the string,
passing NULL to FileOpen, FileOpen failed due to NULL input.
GetAddress wasn't used to "set" the thing it is supposed to set,
Walter thought that Get doesn't mean "Set". Uh-oh, my stomach...
I had a tough day at work, but this just turned it around.
Goran.
Note that this count is almost certainly horribly low, since it only covers what I've
*discovered*, or others have been confused by and reported in this newsgroup, or which
have been sent to me by private email!
The _bstr_t documentation was written by someone who was totally clueless. I'm sure if I
read more of it, I'd find other ridiculous errors. Most of it is incomprehensible at
worst, and it appears that it was *designed* to be confusing and misleading!
joe
As I stated in an earlier message, the Microsoft example is broken AND DOES NOT WORK. It
crashes with an access fault.
I created some example code that demonstrates that (a) the talk about shared BSTRs is
gibberish, because it is vague, confusing, and wrong (b) GetAddress does not affect shared
BSTRs (c) GetBSTR on the LHS of an assignment *does* affect shared BSTRs.
The documentation is just a mess.
See a discussion of the BSTR sharing problems under
http://www.flounder.com/msdn_documentation_errors_and_omissions.htm#_bstr_t::Assign
joe
On Fri, 21 Aug 2009 12:26:20 +0200, Walter Eicher <walter...@nospam.microcrystal.ch>
wrote:
>Hello all,
On Fri, 21 Aug 2009 12:06:00 -0400, Joseph M. Newcomer
<newc...@flounder.com> wrote:
>>If I do it like (2) then it does not work:
>****
>Please define "does not work". This description is without meaning. Do you mean "It
>fails to compile" or "it fails to link" or "it fails to run correctly and returns me an
>HRESULT of <value here>" or "it fails to run correctly and causes an exception" or "it
>fails to run correctly and <your description of observed value here>"? How in the world
>are we supposed to guess what you mean by "does not work"????
>****
Sorry for this, but in the heat of the battle sometimes I loose my
head ;-)
Best regards
Walter