You've reached the internet home of Chris Sells, who has a long history as a contributing member of the Windows developer community. He enjoys long walks on the beach and various computer technologies.
Monday, Oct 25, 1999, 2:55 PM in Fun
Still_Life_with_Aggregate
Still Life with Aggregate
Built using online Lite-Brite.
Jason Whittington
Private DevelopMentor Mailing List
Wednesday, Oct 6, 1999, 5:32 PM
Spirit of the IUnknown
(sung to the tune of "Spirit of the Radio" (Rush, "Permanent waves"))
Words (c) Jason Whittington, 1999
Begin the day with a simple call,
A function unobtrusive
Loads the module that's so elusive
And a matching context means no marshal goo
Off on your way from the factory
Interfaces at your fingers
QueryInterface gets to you a new one
Just Release the pointer when your object's through
Transactional objects crackle with life
While they Service SOAP calls from some ASP
Giving their feedback on the final outcome
Making a call to Abort or Set Complete
All this machinery so that you can use it
Is still quite closely guarded
CreateInstance will get you a new object from the factory
(yeah the factory)
One likes to believe that it's easy to use it,
But the threading models and getting pointers marshaled
shatters the illusion of transparency
the CLSID to marshal was requested by the S-C-M...
F-T-M!
Cookies, From the GIT
For Safety! Ohhhh....For Safe-ty!
Jason Whittington
Private DevelopMentor Mailing List
Friday, Jul 30, 1999, 5:32 PM in Fun
Computer synthesized song to liven up your day...
I just like the idea of a computer singing... If you've seen 2001, you'll recognize the tune.
Sunday, Jun 27, 1999, 5:08 PM
Windows Telephony Programming: A Developer's Guide to TAPI
The Book
This page is dedicated to my book, Windows Telephony Programming: A Developer's Guide to TAPI, from Addison-Wesley. If you'd like to order a copy, you can do so from Amazon.com.
The Table of Contents
- Prologue: The Story of Windows Telephony
- Windows Telephony Architecture (excerpted here)
- Assisted Telephony
- Making a Call
- Telephony Framework
- Answering a Call
- Call Management
- Telephony Service Providers
- The Future of Telephony
The Source
After 6 years of keeping the sample code of my Windows Telephony Programming book up to date, I couldn't do it any more. Since I literally haven't written a TAPI program since I shipped the book (although I wrote tons of them for years before that), I'm was just trying to stay ahead of Microsoft's compiler changes, the service packs and the platform SDKs. I'm already two technology waves beyond TAPI and no longer up on the latest in that space.
So, Robert Bamberg is taking over the support of the source code for the book. He does telephony consulting and is maintaining the code for the book on his site. Thanks, Robert!
Hardware/Software Requirements
I built most of the samples under Windows 95. They should work equally well under Windows 98, but none of the audio applications will work under Windows NT (like tMonitor) unless you're using a TSP that supports the audio media mode. Unimodem under NT4 or Win95 doesn't support audio. Unimodem/V, which can be installed on Win95 and comes out of the box on Win98 and NT5/Windows 2000, does support audio applications, assuming you've got compatible hardware. For the book, I used an external Supra Voice Modem. Nothing else would work (and believe me, I tried everything available at the time). However, there's been other modems built since then. If you'd like to take a look at other possible modems, check out http://www.sunny-beach.net/Modems/Modemlist.htm, which lists a set of modems that Sunny Beach tested for the Personal Receptionist product. No guarantees, though, as I haven't compared these modems myself.
FAQ
Two questions come up again and again:
-
Why doesn't my modem work as a voice modem? This is something to take up
with your modem vendor. Ask about TAPI and Unimodem/V support. Please don't ask
me to debug your modem.
-
How do I do fax with TAPI? I haven't done any fax work with TAPI. My
background is integrated voice response (IVR), not modems. The reason the data
modem stuff is in the book is because I like the movie War Games. If
you'd like to do fax with TAPI, check the TAPI FAQs:
Grant Schenck's website: http://members.home.net/grantschenck/Bruce Pennypacker's website: http://tapifaq.pennypacker.org/
Michael Dunn's website: http://members.home.net/tapifaq/tapi.htm
If you have other questions about TAPI that I haven't covered in my book, you should post them to the following newsgroups: microsoft.public.win32.programmer.tapi and microsoft.public.win95.commtelephony.
TAPI Explorer
I built the TAPI Explorer (tExplorer) to allow me to understand the various capabilities of the telephony devices installed on my system when I was developing TAPI applications and writing my TAPI book. It grew into a utility for showing all line, address and phone capabilities as well as other TAPI settings, e.g. country codes, telephony locations, service providers, etc. If you're running into TAPI errors that you don't understand, TAPI Explorer will help you work through them.
This version has been run and tested on Windows 98, Windows ME, Windows NT 4.0, Windows 2000 and Windows XP and supports TAPI versions 1.4 through 3.1.
VS.NET Source | VC6 Source (previous version)
Monday, Apr 19, 1999, 12:00 AM in Fun
Real Programmers...
Contributed by Liliya Yakupova:
Friday, Apr 16, 1999, 1:07 PM in Fun
Signs that you have hired the wrong COM developer...
- Keeps referring to interfaces as "Thingies".
- Insists that migrating to NT5.0 is a bad idea because the going rate for a rental-threaded apartment is $640.00 a month plus utilities.
- Comes into work one morning dressed as a cowboy and claiming to be "The new marshaller in town".
- Wants to know how to tune his TV to the "RPC Channel".
- Stands up in design meetings, grabs his crotch, and proclaims "Yo! Marshall this! Am I right?".
- Names one of his interfaces "IKnown" and claims that any object that doesn't implement it is doomed to eventually fall victim to a "COM Identity Crisis".
- Spends 2 hours in front of a whiteboard trying to prove that by taking the integral of the GUID generating function, one can discern the total surface area of the application's UI in pixels.
- Pronounces GUID as "gooeey dee".
P.S.
Here's a picture of the t-shirt that Microsoft produced for their 1999 Dallas TechEd that leverages Tony's idea without giving him credit, asking him permission or even notifying him. You lawyers should be able to support you in your retirement with this one, Tony!

BTW, here's one more sign that you've hired the wrong COM programmer (do you think CAT scans will become a normal part of the interview process?):
Anthony Toivonen
Fri 4/16/99 1:07 PM
DCOM Mailing List
Thursday, Apr 15, 1999, 12:00 AM in Fun
The Official Guide to COM Culture
If the things on this page haven't been enough for you, check out Mr. Bunny's Guide to ActiveX.
Friday, Apr 17, 1998, 9:04 AM
Handling Name Collision Using Forwarding Shims
One of the problems with MI is that of name collisions. Imagine the following interfaces:
interface ICowboy : IUnknown {
HRESULT Draw();
};interface IArtist : IUnknown {
HRESULT Draw();
};
Because both
Draw methods have the same signature, using straight MI requires a single shared implementation:
// Ace Powell was a cowboy/artist who lived in the
// western US from 1912 to his death in 1978. I'd
// like to thank Tim Ewald for this fabulous example,
// which I have used to death for years.
class CAcePowell :
public CComObjectRootEx<CComSingleThreadModel>,
public ICowboy,
public IArtist {
public:
BEGIN_COM_MAP(CAcePowell)
COM_INTERFACE_ENTRY(ICowboy)
COM_INTERFACE_ENTRY(IArtist)
END_COM_MAP()
...
HRESULT Draw()
{ /* Act as a cowboy or an artist? */ }
};
Since the implied meaning of
Draw is very different for an artist than it is for a cowboy, wed like to be able to provide two Draw implementations. For that, we a technique long known to the C++ community that Ill call "forwarding shims."The problem is that C++ has no syntax to be able to distinguish methods with the same signature from different bases in the derived class. For example, the following is not legal C++:
class CAcePowell :
public CComObjectRootEx<CComSingleThreadModel>,
public ICowboy,
public IArtist {
public:
BEGIN_COM_MAP(CAcePowell)
COM_INTERFACE_ENTRY(ICowboy)
COM_INTERFACE_ENTRY(IArtist)
END_COM_MAP()
...
HRESULT IArtist::Draw(); // error
HRESULT ICowboy::Draw(); // error
};
However, we can certainly distinguish the methods in individual base classes, e.g.
struct _IArtist : public IArtist {
STDMETHODIMP Draw() { return ArtistDraw(); }
STDMETHOD(ArtistDraw)() =0;
};
struct _ICowboy : public ICowboy {
STDMETHODIMP Draw() { return CowboyDraw(); }
STDMETHOD(CowboyDraw)() =0;
};
Both
_IArtist and _ICowboy are shim classes that implement the method with the conflicting name and forward to another pure virtual member function with a unique name. Since both shims derive from the interface in question, they interfaces IArtist and ICowboy can still appear in the interface map without difficulty:
class CAcePowell :
public CComObjectRootEx<CComSingleThreadModel>,
public _ICowboy,
public _IArtist {
public:
BEGIN_COM_MAP(CAcePowell)
COM_INTERFACE_ENTRY(ICowboy)
COM_INTERFACE_ENTRY(IArtist)
END_COM_MAP()
...
HRESULT ArtistDraw();
HRESULT CowboyDraw();
};
This trick fills the vtables for
IArtist and ICowboy with _IArtist::Draw and _ICowboy::Draw. These functions, in turn, forward to the more derived classs implementation of the ArtistDraw and CowboyDraw. The forwarding shims remove our name conflict at the cost of an extra vtable per shim class, an extra entry per method per vtable and an extra virtual function invocation per call. If this extra cost bothers you, remove it using the standard ATL tricks:
template <typename Deriving>
struct ATL_NO_VTABLE _IArtist : public IArtist {
STDMETHODIMP Draw() {
return
static_cast<Deriving*>(this)->ArtistDraw();
}
};
template <typename Deriving>
struct ATL_NO_VTABLE _ICowboy : public ICowboy {
STDMETHODIMP Draw() {
return
static_cast<Deriving*>(this)->CowboyDraw();
}
};
class ATL_NO_VTABLE CAcePowell :
public CComObjectRootEx<CComSingleThreadModel>,
public _ICowboy<CAcePowell>,
public _IArtist<CAcePowell> {
public:
BEGIN_COM_MAP(CAcePowell)
COM_INTERFACE_ENTRY(ICowboy)
COM_INTERFACE_ENTRY(IArtist)
END_COM_MAP()
...
HRESULT ArtistDraw();
HRESULT CowboyDraw();
};
Credit
Tim Ewald showed me this trick years ago. Jim Springfield showed me how it could be used with ATL. Don Box recommended the ATL_NO_VTABLE optimization.
Copyright
This web page is adapted from the book ATL Internals by Brent Rector and Chris Sells. Copyright � 1998 by Addison Wesley Longman, Inc. All rights reserved.
Friday, Jun 27, 1997, 12:00 AM in Tools
Welcome to MeowMoniker!
Overview
MeowMoniker and Feline are COM objects designed and built by Chris Sells, with a great deal of input from Don Box and Tim Ewald. The MeowMoniker is a custom moniker derived from the CComMoniker class implemented by Don Box, Tim Ewald and Chris Sells.
To contact the authors with suggestions or comments, use csells@sellsbrothers.com, tewald@obelisk-llc.com and dbox@microsoft.com.
MeowMoniker Usage
Microsoft tags every marshalled interface reference packet with the signature MEOW (which they claim stands for Microsoft Extended Object Wire-representation). This binary packet is a serialized interface reference used for inter-apartment activation. Turning this binary packet into a string (via some encoding technique, i.e. Base64) allows a serialized interface pointer to be passed more easily than binary data, e.g. as a command-line argument or in an HTML page.
Monikers, on the other hand, provide a general-purpose way for a client to separate itself from the object binding policy. These object binding polices can be composed and stored in strings. These strings contain a string description of the binding policy and policy parameters. By building a custom moniker that takes a string-ized interface reference as a parameter, a client can use the standard moniker-based binding algorithm and bind to a running object via an interface reference. The MeowMoniker is an implementation of a moniker that can compose display names out of interface pointers and bind to objects via its display names.
To create a MeowMoniker from an interface pointer, MeowMoniker.dll exposes the CreateMeowMoniker() function:
STDAPI CreateMeowMoniker(
IUnknown* punk, // Pointer
to the interface to be marshaled
REFIID riid, // Reference to the
identifier of the interface
DWORD dwDestContext, // Destination context
DWORD mshlflags, // Reason for
marshaling
IMoniker** ppmk); // Indirect
pointer to the moniker
e.g.
IMoniker* pmk;
hr = CreateMeowMoniker(punkObject,
IID_IUnknown,
MSHCTX_DIFFERENTMACHINE,
MSHLFLAGS_NORMAL,
&pmk);
To obtain the MeowMoniker's display name, use the GetDisplayName() member function of the IMoniker interface:
HRESULT GetDisplayName(
IBindCtx *pbc, // Pointer to bind context to
be used
IMoniker *pmkToLeft, // Pointer to moniker
to the left in the composite
LPOLESTR *ppszDisplayName); //Indirect
pointer to the display name
e.g.
IBindCtx* pbc;
hr = CreateBindCtx(0, &pbc);
wchar_t* pwszDisplayName;
hr = pmk->GetDisplayName(pbc, 0, &pwszDisplayName);
To parse a display name composed by the MeowMoniker, OLE32.dll exposes the MkParseDisplayName() function:
WINOLEAPI MkParseDisplayName(
LPBC pbc, // Pointer to the bind context
object
LPCOLESTR szUserName, // Pointer to display
name
ULONG FAR *pchEaten, // Pointer to the
number of characters consumed
LPMONIKER FAR *ppmk); // Indirect
pointer to the moniker
e.g.
IBindCtx* pbc;
hr = CreateBindCtx(0, &pbc);
IMoniker* pmk;
ULONG cchEaten;
hr = MkParseDisplayName(pbc,
pwszDisplayName,
&pmk);
To bind to a object, use the BindToObject() member function of the IMoniker interface:
HRESULT BindToObject(
IBindCtx *pbc, // Pointer to bind context
object to be used
IMoniker *pmkToLeft, // Pointer to moniker
that precedes this one in the composite
REFIID riidResult, // IID of interface
pointer requested
void **ppvResult); // Indirect
pointer to the specified interface on the object
e.g.
IUnknown* punk;
hr = pmk->BindToObject(pbc, 0, IID_IUnknown, (void**)&punk);
Note: The MeowMoniker does not current support composition or the IMoniker
interface member function BindToStorage().
Feline Usage
Since neither VB nor VBScript supports calling CreateMeowMoniker() and since VBScript has no equivalent of the VB function GetObject(), the Feline object provides a dual-interface for making display names out of interface pointers and parsing moniker display names:
[
object,
uuid(CB18CB8E-C7CC-11D0-9A44-00008600A105),
dual,
helpstring("DIFeline Interface"),
pointer_default(unique)
]
interface DIFeline : IDispatch
{
[id(1), helpstring("Returns the Meow Moniker name of an
interface pointer")]
HRESULT GetDisplayName([in] IDispatch* pdisp, [out, retval]
BSTR* pbstrName);
[id(2), helpstring("Returns an interface pointer given
any moniker display name")]
HRESULT ParseDisplayName([in] BSTR bstrName, [out, retval]
IDispatch** ppdisp);
};
The following is an example Active Server Page that creates an object on the
server, creates a display name using the object's interface pointer and uses
the display name to create a client-side script. The client-side script uses
its own instance of a feline object to parse the display name and bind to the
object created on the server-side.
<HEAD>
<TITLE>feline.asp</TITLE>
</HEAD>
<BODY>
<object classid="clsid:CB18CB8F-C7CC-11D0-9A44-00008600A105"
runat=server
id=feline>
</object>
<object classid="clsid:7CF322E0-29A9-11D0-B367-0080C7BC7884"
runat=server
id=pt>
</object>
<object classid="clsid:CB18CB8F-C7CC-11D0-9A44-00008600A105"
id=feline>
</object>
<script language=vbscript>
dim pt
set pt = feline.ParseDisplayName("<%=
feline.GetDisplayName(pt) %>")
pt.x = 100
pt.y = 200
document.write pt.x & ", " & pt.y
</script>
</BODY>
</HTML>
CComMoniker Implementation
The MeowMoniker derives most of its functionality from CComMoniker, provided in mkbase.h and mkbase.cpp. This base class implements IMoniker, IParseDisplayName, IROTData and IMarshal (for marshal-by-value). This implementation uses the moniker's display name as the persistent state. The custom moniker implementor deriving from CComMoniker must provide the CSLID of the moniker as the single template parameter (used in the implementation of the GetClassID() member function of IPersist and the GetUnmarshalClass() member function of IMarshal). The implementor may override any of the base class's member functions but must implement these three IMoniker members:
STDMETHODIMP BindToObject(
IBindCtx* pbc,
IMoniker* pmkToLeft,
REFIID riidResult,
void** ppvResult);
STDMETHODIMP GetDisplayName(
IBindCtx* pbc,
IMoniker* pmkToLeft,
LPOLESTR* ppszDisplayName);
STDMETHODIMP ParseDisplayName(
IBindCtx* pbc,
IMoniker* pmkToLeft,
LPOLESTR pszDisplayName,
ULONG* pchEaten,
IMoniker** ppmkOut);
As a aid in parsing display names, the CComMoniker class provides the following helper function:
bool MatchesProgID(
const wchar_t* pwszDisplayName, // Display name
being parsed
const wchar_t** ppwszDisplayParam); // Pointer to
character past :
This function checks the display name for a leading ProgID or
VersionIndependentProgID followed by a colon and returns a pointer to the first
character of the display name parameter(s), i.e. one character past the colon.
The implementation of this function requires the derived class to implement the
following member functions:
virtual const wchar_t* ProgID() =0;
virtual const wchar_t* VersionIndependentProgID() =0;
e.g.
const wchar_t* ProgID() { return L"dm.meow.1"; }
const wchar_t* VersionIndependentProgID() { return L:dm.meow"; }
CoMeowMoniker Implementation
The MeowMoniker is an ATL object named CoMeowMoniker. It derives from CComMoniker and provides an implementation of the required members only. The bulk of the implementation is contained in the two member functions, MarshalInterface() and UnmarshalInterface(). These two member functions manage the Base64 encoding and decoding of the interface pointer. The actual Base64 implementation is kept in Base64.cpp.
CoFeline Implementation
The Feline is an ATL object named CoFeline. Its implementation of GetDisplayName() uses a MeowMoniker. Its implementation of ParseDisplayName() uses MkParseDisplayName() so that any moniker's display name can be used.
Download
Here.
YACL
The implementation of the MeowMoniker is based on utilities provided in the
YACL (Yet Another COM Library), developed and maintained by Don Box and
available at Don's YACL web site.
The pieces of YACL
that I have used, I've included in the appropriate directories.
Revisions
6/15/98
- Updated MeowMoniker to perform GetSizeMax properly.
- Updated MeowMoniker and CComMonikerBase to use CComPtr and CComQIPtr instead of SmartInterface.
- Removed use of HRESULTEX and therefore the use of C++ exception handling.
- Moved some includes around.
- Reduced RelMinDepend build from 89KB to 80KB. Could probably reduce it more if I could find Matt Pietrek's tinycrt and stop using the real CRT.
Copyright
MeowMoniker, copyright (c) 1997, Chris Sells.
Feline, copyright (c) 1997, Chris Sells.
CComMoniker, copyright (c) 1997, Don Box, Tim Ewald and Chris Sells.
YACL, copyright (c) 1997, Don Box.
Extensions to YACL, copyright (c) 1997, Tim Ewald and Chris Sells.
All rights reserved. NO WARRANTIES ARE EXTENDED. USE AT YOUR OWN RISK.
Sunday, Jan 1, 1995, 12:00 AM in Colophon
Initial Launch
This site was launched sometime in 1995. I have no idea when. It was just a home page with a set of links I wanted to share with my students.
No older posts 2640 newer posts