home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
msdn_vcb
/
samples
/
vc98
/
sdk
/
com
/
inole2
/
errata.txt
< prev
next >
Wrap
Text File
|
1995-05-09
|
17KB
|
451 lines
===========================================================
INSIDE OLE BY KRAIG BROCKSCHMIDT
COMPANION DISC
COPYRIGHT (C) 1995 BY KRAIG BROCKSCHMIDT
===========================================================
Corrections to Printed Text of Inside OLE
Acknowledgements:
My thanks also to Paul Gunn for reviewing some of the text.
Addendum: OLE And Unicode
It may not be clear from the book text itself that the OLE
API functions and interfaces defined for Win32 operating
systems are 100% Unicode, even on an ANSI platform such as
Windows 95. For this reason, ANSI applications have to
convert strings between the two character sets when working
with certain OLE APIs and interfaces. You'll see such places
in the sample code, conditionally compiled using the
WIN32ANSI symbol. (If the symbol is not set, the compilation
is 100% Unicode.)
In short, any string that comes back from OLE contains Unicode
characters, and any string you send to OLE has to contain the
same. The samples convert strings on a case-by-case basis, as
needed. There are, however, some cases where you will not
see an explicit conversion in the code, specifically where
an OLE API function is concerned. The master header file
INC\INOLE.H, which is included with all the samples, will redefine
specific OLE API functions to redirect them to ANSI versions
implemented in the helper library found in the INOLE directory.
Functions found there inside ANSI.CPP will call the Unicode
OLE function converting input and output strings as necessary.
Addendum: A global comment about the printed code:
All the code as it appears in the printed text is oriented
around a native Unicode application for the sake of brevity.
The actual sample code compiles to ANSI as well as 16-bits,
so there will be a few minor differences where strings
and string manipulation functions are concerned.
In addition, you'll see char, TCHAR, and OLECHAR used for
various character types. char will force ANSI characters
regardless of all other conditions; TCHAR will conditionally
compile to ANSI or Unicode depending on the UNICODE symbol
(see BUILD.TXT); OLECHAR is always Unicode (equivalent to WCHAR)
even on ANSI-only platforms such as Windows 95.
You'll see string literals wrapped in either the TEXT or
OLETEXT macro. The TEXT macros conditionally create an
ANSI or Unicode string depending again on the compiler flags.
The OLETEXT macro, defined in INC\BOOK1632.H, always creates
a Unicode macro. Both macros are defined as no-ops for
16-bit compilations.
Finally, the INC\BOOK1632.H file contains macros to hide
the differences between Win16 and Win32 code. This results
in cleaner samples. So if you see a function call in the
code that you know is not available or part of the API for
the system you're working in, it's probably defined in this file.
Page xxiv: A clarification
The "Windows Software Development Kit (SDK)" included with
Visual C++ isn't the complete Win32 SDK that Microsoft
provides separately for Windows 95 and Windows NT (3.5 and
3.51). A few of the book's samples require pieces of the
Win32 SDK, specifically the MIDL compiler used to compile
custom interfaces in Chapters 6 and 9. You will need
the full Win32 SDK to compile CHAP06\IANIMAL, CHAP06\IKOALA,
and CHAP09\IDESCRIP.
It is also important to note again that Visual C++ 2.0
and 2.1 do not include the header and import library for
the standard Windows 95 and Windows NT 3.51 OLE UI Library,
OLEDLG.DLL. The files OLEDLG.H and OLEDLG.LIB, which are
used in the samples by default, are found in the Win32 SDK
products for either platform as well as later versions of
Visual C++ 32-bit.
Page 55: Table 1-1 BUILD directory
The binaries included on the companion disc were compiled
and tested on Windows NT 3.51. Perfect operation on Windows 95
is not guaranteed as Windows 95 was not yet released when
this book was published.
Page 137: Second paragraph, end of second line in that paragraph
"RELEASEINTERFACE" should be "ReleaseInterface"
Page 145: First paragraph
Lo and behold my wife and I bought another car after I wrote
this chapter, and I gave away the Datsun 610 as a trade in.
So I now drive an 82 Honda Accord.
Page 168: Legend on Figure 3-2
The label for "*" should read "only available under 16-bits
with OLE 2.02 and later."
Page 199: Note near top of page
In the future Microsoft will include these files as part of
the Win32 SDK outside of the CDK. At the time of writing,
however, the CDK was the only source for these files.
Page 247: Footnote 6
Windows NT 3.5 actually does allow a client to ask for any
class factory interface on a local server. Windows NT 3.51
is no different. However, an interface like IClassFactory2
does not have marshaling support at the time of writing.
Page 273: CKoalaClassFactory::CreateInstanceLic
This function should not call the classes' own RequestLicKey
because the latter will fail when the machine is not globally
licensed. For this reason, replace this code:
hr=RequestLickey(&bstrTemp);
if (FAILED(hr))
return hr;
with this code:
OLECHAR szLic[256];
mbstowcs(szLic, g_szLic, sizeof(g_szLic));
bstrTemp=SysAllocString(szLic);
if (NULL==bstrTemp)
return ResultFromScode(E_OUTOFMEMORY);
Page 316: Reference to OLEDLG.DLL at end of second paragraph
The text says that the samples "attempt" to use OLEDLG.DLL.
If you do not have the necessary header files for this library,
see BUILD.TXT for information on using the version of the library
included with Visual C++ (which would apply to another compiler
for the most part as well).
Page 325: Reference to [async] in the second paragraph after the code.
[async] actually doesn't do anything at the time of writing.
The marshaling code generated by MIDL will still generate
synchronous calls.
Page 380: A clarification to association by bit pattern
GetClassFile processes all the FileType entries for a CLSID
separately such that any single match for any individual
pattern entry will associate the file with the CLSID. This
is obviously what should happen, as it allows multiple file
formats to map to the same CLSID. The pattern matching
process can easily be confused to mean that all patterns
must match instead of only one, which is incorrect.
Pages 405-406: Clarification to footnote and discussion in general
The reason that IPersistStreamInit is not derived from
IPersistStream (although it is still polymorphic) is that
some objects may need to treat the two interfaces exclusively.
That is, an object may very much require the
IPersistStreamInit::InitNew semantics such that it does not
want to give clients the impression that IPersistStream is
suitable. In other words, an object that immplements
IPersistStreamInit may not support IPersistStream through
its QueryInterface. Those objects that can handle the
lack of InitNew, using it only for optimization purposes,
can implement both interfaces and provide them both through
its QueryInterface. The Polyline sample is such an object.
Page 471: Concerning the samples and Windows 95
At the time of writing, these samples suffered from
"Invalid Page Fault" crashes on Windows 95 Build 460.
They do, however, work fine on Windows NT. You may encounter
similar problems with beta versions of Windows 95
yourself, and if you find the problem to actually be in
the samples, please let the author know.
Page 502: Behavior of ReleaseStgMedium
When the STGMEDIUM structure contains an IStorage or
IStream, ReleaseStgMedium will call BOTH pUnkForRelease->Release()
if non-NULL as well as IStorage::Release or IStream::Release.
That means that a data source providing IStorage or IStream
types will need to call IStorage::AddRef or IStream::AddRef
in addition to supplying a pUnkForRelease if that source wants
to maintain ownership of the medium.
Page 507: A note about STATDATA
The client that enumerates advise connections must be sure
to free any non-NULL DVTARGETDEVICE structure inside the
FORMATETC of STATDATA with CoTaskMemFree and must also call
IAdviseSink::Release. The enumerator object that creates these
structures must allocate the DVTARGETDEVICE with CoTaskMemAlloc
and must create or AddRef the IAdviseSink pointer.
Page 562: Code for Freeloader's CFreeloadDoc::Paste
The code, as printed, uses the data obtained from the clipboard
after CloseClipboard is called, which is incorrect. The
code should appear as follows:
HGLOBAL hMem;
if (!OpenClipboard(hWndFrame))
return FALSE;
/*
* Try to get data in order of metafile, dib, bitmap. We set
* stm.tymed up front so if we actually get something a call
* to ReleaseStgMedium will clean it up for us.
*/
stm.pUnkForRelease=NULL;
stm.tymed=TYMED_MFPICT;
hMem=GetClipboardData(CF_METAFILEPICT);
if (NULL!=hMem)
cf=CF_METAFILEPICT;
if (0==cf)
{
stm.tymed=TYMED_HGLOBAL;
hMem=GetClipboardData(CF_DIB);
if (NULL!=hMem)
cf=CF_DIB;
}
if (0==cf)
{
stm.tymed=TYMED_GDI;
hMem=GetClipboardData(CF_BITMAP);
if (NULL!=hMem)
cf=CF_BITMAP;
}
stm.hGlobal=OleDuplicateData(hMem, cf, NULL);
CloseClipboard();
Page 573: Correction to IDataObject::GetData code
Because DATATRAN is using pUnkForRelease to maintain
ownership of its data, it has to call AddRef through
any IStorage or IStream pointer returned from GetData.
Accordingly, the code shown at the top of this page is
insufficient and should appear as follow:
for (i=0; i < cItems; i++)
{
cb=SendMessage(hList, LB_GETTEXT, i, (LPARAM)&pRen);
if (LB_ERR!=cb)
{
/*
* Check if the requested FORMATETC is the same as one
* that we already have. If so, then copy that STGMEDIUM
* to pSTM and AddRef ourselves for pUnkForRelease.
*/
if (pFE->cfFormat==pRen->fe.cfFormat
&& (pFE->tymed & pRen->fe.tymed)
&& pFE->dwAspect==pRen->fe.dwAspect)
{
/*
* ReleaseStgMedium will Release both storage
* and stream elements regardless of the value
* of pUnkForRelease, so we have to AddRef the
* element and bump our own ref count here.
*/
if (TYMED_ISTORAGE==pRen->fe.tymed)
pRen->stm.pstg->AddRef();
if (TYMED_ISTREAM==pRen->fe.tymed)
pRen->stm.pstm->AddRef();
*pSTM=pRen->stm;
AddRef();
return NOERROR;
}
}
}
Page 670: Additional comments about dual and custom interfaces
Versions of Visual Basic later than 3.0 and many versions of
Visual Basic for Application support direct calling
of dual and vtable custom interfaces. This eliminates most
of the advantages that dispinterfaces once enjoyed, that is,
the exclusive ability for VB to call that interface. Now that
VB can call any interface, using dual interfaces and custom
vtable interfaces should be the typical mode of operation,
since much greater performance can be achieved with vtable
binding. If you want to have dispID binding still, then
a dual interface is encouraged.
Page 677: Concerning Beeper3.
Error objects (as described more below) also solve the problem
of returning exceptions from dual interfaces. Beeper3 as it
exists does not return exceptions, so an additional sample,
Beeper3a, is provided to demonstrate the right way to use
error objects from vtable interfaces (including the vtable
portion of a dual interface)
Pages 701-706: About error objects
Besides the multi-threaded issue, error objects were invented
to allow vtable interfaces, dual interfaces, and those implemented
using the standard dispatch object (demonstrated in Beeper 5) to
return exception information.
As stated in the text, ITypeInfo::Invoke will call GetErrorInfo
to retrieve an exception, but it will do this only for vtable
functions that return an HRESULT and return DISP_E_EXCEPTION.
Beeper3, however, doesn't do this, as its vtable functions do
not return HRESULTs. Therefore you will not see exceptions from
Beeper3.
A modification of Beeper3 that does this correctly is the
sample CHAP14\BEEPER3A, whose custom interface does return
HRESULTs and will return DISP_E_EXCEPTION when it has filled
an error object. Please refer to that example in preferance
to Beeper 3.
Page 708: Third paragraph, reason why HRESULT is returned.
HRESULT is needed as a return value from dual interface
members not only for marshaling but also for support of
error objects, as described above.
Page 710: Concerning Beeper5
This sample could return exceptions through error objects if it
was modified to return HRESULTs from its vtable members instead
of other types. In short, the same changes that took Beeper3 to
Beeper3a apply to Beeper5. A code example for this is not,
however, provided, and is left as an exercise to the reader.
As it stands, Beeper5 doesn't return exception information.
Page 736: Concerning the test program CHAP15\VBSQUARE
This test script works only with versions of Visual Basic
after 3.0.
Page 808: Cosmo and the registry
If you encounter any registry trouble with Cosmo18 after
running Cosmo14, go to the registry and delete all entries
for Cosmo, then reregister Cosmo18.
Page 881: CHAP18\COSMO1.0
This sample has not been thoroughly tested, as OLE 1 on 32-bit
platforms is officially not supported by Microsoft. If this
sample fails to work under 32-bits, try a 16-bit compilation,
which will still interoperate with the 32-bit Cosmo18.
Page 997: Code listing for CPatronDoc::Rename
The line at the top of the page should read:
INOLE_RegisterAsRunning(this, pmk
, ROTFLAGS_REGISTRATIONKEEPSALIVE, &m_dwRegROT);
Page 999: Code listing for CPage::NotifyTenantsOfRename
The second conditional statement at the top of the
page should appear as follows:
if (NULL!=pmkWild)
{
INOLE_RegisterAsRunning(this, pmkWild
, ROTFLAGS_REGISTRATIONKEEPSALIVE, &m_dwRegROTWild);
pmkWild->Release();
}
Page 1114: IOleControlSite::FreezeEvents
When a container freezes events, it really tells the control
that the container will not process those events, but the
control is still allowed to fire them. In other words,
this function tells a control to not expect any behavior
from the container when events are fired until FreezeEvents(FALSE)
is called. A container has to robustly handle events that
it receives when events have been frozen
Page 1139: Second paragraph under "Notes on Polyline..."
Polyline on 32 bits does not supply a ToolboxBitmap32,
nor does the 16-bit version supply a ToolboxBitmap.
Page 1164:
Make yourself a big "Yippee! You Made It!" note
on this page. Give yourself a reward when you finish
reading this mighty tome. You deserve it! And thank
you for reading it as well!