This is a set of .NET, COM and Win32 tools that Chris Sells has built and
contributed to the world. You may use them without royalty (and without
support) in your compiled code. You may not redistribute the source code.
A mention in the documentation of your products is always appreciated. Enjoy!
P.S. I have no idea where the picture at the top of this page came from
-- feel free to use it with the exact same number of permissions I have
to use it, i.e. none.
Thu, 9/3/09
Windows 7 took away a feature I use all the time -- Search the Internet:
Here's what I did all day, every day in Windows Vista: Ctrl+Esc to bring
up the Start menu, then I start typing. If I'm searching on my HD, I
immediately get matches and I can choose one with just the arrows and the
Enter key. If I'm typing in the name of a program in the Start menu, I get
those matches and choose one. If I want "calc" or "notepad" I can just type
those and those work.
However, 80% of the time, I want to search the internet, so enter my
search term, optionally including attributes like "site:", I press,
down-arrow once, highlight "Search the Internet" and press Enter. This
brings up my default browser with my search results in my default search
engine without me having to move the mouse or open the browser and wait for
the home page or even decide where I want the search results to come from
until after I've entered my search phrase.
And we took it out of Windows 7. : (
But, Shawn VanNess has shown me how to put it back! : )
Download this
zip file, execute the .reg file, press Yes and OK a bunch, kill and restart the
explorer.exe process and the next time you do the Ctrl+Esc+type+something
dance, you'll see your old friend "Search the Internet" right back on the
Start menu where Bill intended it to be. Thanks, Shawn!
Discuss
Wed, 4/11/07
Show Me The Template is a tool for
exploring the templates that comes
with the controls built into WPF for all 6 themes. In addition to the
learning experience this provides (I'm constantly figuring stuff out about
how WPF works by reading the default templates), it's also a handy way to
start when you're building your own templates instead of starting from
scratch (particularly for control templates).
Discuss
Tue, 7/30/06
I updated the SDK RegistrySettingsProvider to implement
IApplicationSettings and built a sample to demonstrate how to integrate it
(or any .NET 2.0 custom settings provider) with the settings
designer-generated code.
Enjoy.
Discuss
Sun, 7/30/06
To capture the work that Doug and I did to make Indigo (WCF)
and Avalon (WPF) work together, I tore up
our PDC sample application into a set of simpler technology samples. To
make it fun for myself, as part of these samples, I built a little library
for converting numbers into strings of English words, e.g. 4 is "four:"

To drive home the point (of which there wasn't any because
the sample had nothing whatever to do with number to English phrase
conversions), I spent some time polishing the algorithm so that it handled
decimal points:

and when that didn't satisfy me, I added large numbers and
negative numbers:

Before writing this code, I searched the net and didn't find
any algorithms that handled both negative numbers and decimal points, let
alone for .NET or in the number of lines of code to which I cut it down (93,
including comments). I know it's not useful, but it was fun. If you want the
code, you can get it by
downloading the .NET 3.0 Cross Technology samples and checking out the
WinSDK_Samples\CrossTechnology\WpfDataBindingToWcfResults\service\NumberUtility.cs
file. I built the file to be dropped into any .NET 2.0+ project (and even
.NET 1.x projects, if you remove the "using System.Collections.Generic"
statement at the top of the file -- I don't actually use generics),
regardless of whether you're using Avalon or Indigo or not.
Enjoy.
Discuss
Tue, 11/25/03
CsvFileTester is a tool inspired by
Shawn Wildermuth's ExcelFileTester, which he wrote 'cuz I kept asking him
how to do queries on .xls files. However, because the Excel query language has
no where or order by clauses, I gave that up in favor of comma-separated text
files.
I wrote CsvFileTester (with Shawn's help) to explore the ADO.NET/ODBC/JET
support for CSV files and I was amazed at how comprehensive the support was.
And, since I can never remember the syntax and limitations between one use of
Jet expression syntax and the next, I put a bunch of samples in the combobox.
Enjoy.
Wed, 8/6/03
FormatDesigner is an application to experiment with the format strings used to
format data in String.Format and various type's ToString functions.

Click here to launch the application
directly (requires the
.NET Framework 1.1).
Click here to download the source code.
Enjoy.
Wed, 6/18/03
Tired of the XmlSerializer's generic "File or assembly name
ctewkx4b.dll, or one of its dependencies, was not found" exception?
The XmlSerializerPreCompiler tools
checks to see if a type can be serialized by the XmlSerializer class and if
it can't, shows the compiler errors happening behind the scenes so that the
type can be modified. Enjoy.
This just in: Mathew Nolton has posted
a GUI front-end to my XmlSerializerPreCompiler that you might find
useful. Thanks, Matt!

Fri, 6/13/03
The fact that Windows XP Find in Files only searches files
with known file extensions drives me crazy because it skips, among other
things, .cs files. Every time I set up a new system, I have to
re-figure out how to fix this. To facilitate that, I put together
a .reg file that will
search all unknown file extensions as text files. Enjoy.
Fri, 1/10/03
In writing the resources chapter of my WinForms book, I
found that there was no single utility for displaying the resource contents of
assemblies, .resx files and .resource files (even embedded .resources files)
in a way that made sense to me. So, I built
one and called it ResourceExplorer.

ResourceExplorer is very simple and could stand some
extension to show specific resources at images, text, data, etc, but it
certainly served my needs, especially when it came to understanding the
usage and limitations of the ResourceReader (for reading .resources files)
and the ResXResourceReader (for reading .resx files). Enjoy.
Sun, 10/13/02
Scancode
Mapper is
a GUI tool for setting the Scan Code Mapper for Windows Registry settings
for Win2K+:

As an example of what this tool does to the Registry,
this .reg file turns off the CapsLock key. Of course, changing scancode mappings is a risky business,
so be sure of what you're doing before committing the changes and restarting
Windows. No warranties extended. Use at your own risk. Enjoy. : )
9/10/02
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)
Fri, 5/17/02
XsdClassesGen is a Custom Tool
Add-In to VS.NET 2002 & 2003 to generate type-safe wrapper classes for serializing to
and from XML documents. It takes as input an XSD and produces the C# or
VB.NET code to do the serialization using the XmlSerializer. This is really
just the output of running xsd.exe /classes, but integrated directly into
VS.NET.
If you'd like to know more about what a custom tool is and
how to build your own, check out CollectionGen.
Also, Atif Aziz used some of my custom tool code and built
a generic VS.NET code generator shim that allows you to build a code
generator that plugs into VS.NET by implementing a single method.
And, as if that weren't enough,
Stephane Tombeur has posted the code to VS2005. Thanks, Stephane!
Thu, 4/12/02
USE THIS FILE WITH CARE. It causes problems with image
lists for .NET EXEs that don't also use the same manifest file.
Just drop this
devenv.exe.manifest file next to devenv.exe in your VS.NET install
directory and the next time you start VS.NET under XP, it'll look mostly the
same! (well, maybe a little different : )
Wed, 4/10/02
[Note: As of 5/5/03, the functionality of CollectionGen has been sucked
into Eric
Smith's CodeSmith. I asked Eric to take on these features because
CodeSmith does all of what CollectionGen does and more. All new feature
requests/bug reports should go his way.]
CollectionGen is
a Custom Tool Add-In to VS.NET 2002 & 2003 to generate type-safe collections. As it turns out, I did almost none of
the work. Jon Flanders figured out how to add a custom tool.
Shawn Van Ness
implemented
the template for type-safe collections. I just put it together.
CollectionGen is an add-on to generate code for type-safe collections
until we have templates in C# (likely) and VB (unlikely). The benefit of a
type-safe collection, of course, is that you can use it without having to
cast items to and from objects. Also, Shawn has been very careful to
implement a collection class that is very efficient for both reference types
and value types.
Once you've setup it up and defined your collections in a collection
definition file in your project, you'll have type-safe collection classes
generated as part of your design-process, as shown here:

Figure 1: collections.xml collection definition file

Figure 2: collections.xml and generated collection.cs implementation
file

Figure 3: CollectionGen custom tool add-in associated with the
collections.xml file

Figure 4: Generate type-safe collection code
Enjoy!
Also, Atif Aziz used some of my custom tool code and built
a generic VS.NET code generator shim that allows you to build a code
generator that plugs into VS.NET by implementing a single method.
4/6/2002 (updated 3/4/2005)
RegexDesigner.NET is a powerful visual tool for
helping you construct and test .NET Regular Expressions. When you are
happy with your regular expression, RegexDesigner.NET lets you integrate it
into your application through native C# or VB.NET code generation and
compiled assemblies (usable from any .NET language).

Features:
- Full source
- Interactive matching of .NET regular expressions.
- Syntax highlighted match results, including
zero-length matches and hidden characters.
- Tooltips to display matched groups.
- Regular expression matching, replacing and splitting.
- Regular expression projects to save expressions, text
to match and all regex options.
- Full code generation for C# and VB.NET for all regex
operations.
- Compiled assembly generation.
- Full online help.
Testimonials
Anthony Bova had this to say about RegexD: "Thank you for this program. I
had some nasty text files to parse and this cut through it like a hot knife
through butter!"
Fri, 3/8/02
Inspired by my need to know who was calling without hauling
my butt off the couch to look at the caller ID on the phone across the room
(my father always said that "laziness is the mother of invention"),
I built a couple of C# classes for managing an IM
connection and an IM session. The test client is a console application
that just sends messages and
dumps whatever it gets from the IM server to the console, but I think it
would serve as the code is the beginnings of a real IM client.
It does the MD5 stuff properly and handles being redirected to another IM
server, so the hard part of the protocol is already implemented. The sample
itself is a handy little program that logs in as an IM user, sends a message
to another IM user and logs back off again. Perfect for annoying your office
mates. Enjoy.
BTW, Harry Pierson
has made a number of updates to this core code to support his
full-blown
.NET IM client application. Check it out!
Sat, 2/16/01
Genghis is a set of extensions built on top of .NET and
integrated with WinForms to provide application-level services in the same
flavor as the Microsoft Foundation Classes. Genghis gets its name as the
functional heir to Attila, a similar set of functionality built on top of ATL.
Tue, 1/22/02
Are you building and deploying .NET applications in a secure
environment, e.g. over the intranet or the internet? If so, they you've
probably mourned the loss of the binary and SOAP formatters that can
automatically serialize a graph of objects that are marked as [Serializable]
and that may also implement ISerializable and IDeserializationCallback. Both
of these formatters are dependent on reflection, which will not be available
in a more restrictive security environment. Likewise, even
ISerialization.GetObjectData is verboten if you wanted to do this kind of
thing yourself. As far as that goes, [Serializable] and ISerialization
should be forbidden in a secure environment, as it allows a client to
get and set the private variables of an object, potentially causing harm.
Still, security is the enemy of usability, to paraphrase
Keith Brown. So, in the spirit of a balancing the design need for objects
that can serialize themselves with the goal of complete disclosure in a
secure world, I've built my own "safe" formatter. It only uses facilities of
the runtime that work in the most secure environment of the default settings
for the internet zone. So that objects can guard themselves against
malicious data, I define a new interface called ISafelySerializeable that
they need to implement to support this serialization facility. The protocol
is exactly the same as ISerializable, so if that interface is already being
implemented, the implementation of GetObjectData can be shared between both
interfaces.
Currently, the code is in alpha and is riddled with TODO
statements, but its functional enough today for actual usage.
My SafeFormatter and test harness are available
for your feedback. Enjoy.
1/6/02
If you haven't seen it yet, check out the
VS.NET Fun Facts piece that started
as praise and bitching about VS.NET, but turned into something pretty useful
if you'd like to get the most out of VS.NET.
Wed, Oct 10, 2001
I've updated CorPub to show *all* managed AppDomains by initializing the COR
debugging sub-system prior to enumerating them. Thanks to
Atif Aziz for the tip.
Thu, Sept 13, 2001
I built the CorPub utility when my friend Jason
pointed me at the .NET corpub.idl interfaces (his exact words were
"ICorPublishProcess rocks!"). CorPub lists the managed processes on the current
machine and the AppDomains in each process, as follows:
Managed process 0xa54: D:\project\mine\RegexPlorer\bin\Debug\RegexPlorer.exe
AppDomain 0x1: RegexPlorer.exe
Managed process 0xdc8: C:\vs.net\Common7\IDE\devenv.exe
AppDomain 0x1: DefaultDomain
Managed process 0x1ec: C:\PROGRA~1\MICROS~2.NET\FRAMEW~1\Bin\ildasm.exe
AppDomain 0x1: DefaultDomain
It's fun for spelunking. Enjoy.
NOTE: .NET beta 2 is required to run this utility.
Mon, 26 Jun 2000
To deal w/ the number of wrapped URLs I get in my email box, I built
UrlRun. It checks the clipboard for an URL, no matter how broken,
strips spaces, newlines and greater thans out of it and runs IE. To handle an
URL as show above, select it, copy it to the clipboard and launch UrlRun.exe. I
keep it on my QuickStart toolbar.
If you happen to be using Outlook 2000 or Outlook XP, Tim Tabor has built an
UrlRun add-in that does the magic by simply right-clicking on a mangled
URL that's you've selected. It's pure sex.
Wed, Aug 8, 2001
xmlValid is simple command line utility that will
check an xml file for well-formedness and, optionally, will validate it against
a supplied XML schema file (xsd). I built it to check that my site's HTML files
were well-formed (and therefore XHTML-compliance), but it's got all kinds of
other uses, including checking .NET .config files. Source is included. Enjoy.
Usage: xmlValid.exe xmlFile [xsdFile]
Note that this utility requires .NET beta 2 to be installed.
Wed, Aug 8, 2001
Whenever I set up a new machine (which happens a lot as WinXP and .NET go
through their beta & RC cycles), I always need to manually set up the
completion character (to TAB, of course) in the Registry.
Shawn VanNess
posted a .rgs file that would set this up without the lengthy search
through the Registry. Inspired by Shawn, here's my own
completionChar.reg that doesn't require a program to parse .rgs files
(which doesn't come with Windows).
BTW, if you don't know about the command shell's Completion Character, stop
right now, run the completionChar.reg file,
start up a WinNT/Win2K/WinXP command shell, type "cd c:\p[TAB]" and watch while
the shell expands it to "cd C:\Program Files\" for you. If you have other
directories that start with "c:\p", continue to hit [TAB] to cycle through
them. This works for any directory or file name and it boosts my productivity
by about 100% on the command line. I can't live without it!
Wow. I'm impressed as all get out. Hugh Brown
has reverse-engineered Gen<X> as one of the tests of his
NullScript implementation. I wish I would have had this when I started
Gen<X> a couple of years ago. It would've saved me figuring out how ASP
did it.
My thinking along these lines years ago led me to go the opposite way, i.e. I
built a front-end ASP parser that generated script for VBS. I called it
TextBox (which, as a Win32 programmer, I should've realized was a
terrible name...).
Here's my
moniker wizard that includes the framework used by
the Basic Monikers.
The great and powerful Tim Ewald (author of
Transactional COM+: Building Scalable Applications and personal
friend of mine) put together a handy little set of COM+ classes
and utility functions in a concise header file that he has graciously
allowed me to host. Among my favorites are IsInActivity, IsInTransaction,
IsSecurityEnabled, GetCallersName, IsCallerInRole, and parameterized
versions of CoGetObjectContext and GetAspObject (which is even cooler than my
CAspPtr). Download the code!
Buy the book! Feed your brain!
I got tired of not having getopt under Win32 and the best version to port
doesn't handle slashes (as per the Windows standard) or @files for arguments
and it requires you to give away the source for every app that uses it, so,
inspired by my friend Josh Gray, I built my
own. It supports typed flags and params, @file support and building
full usages on the fly.
Plus, the latest version has support for parsing ANSI or Unicode argfiles, as
provided by Johan Nilsson.
Thanks, Johan! Also, I've added a contribution by
Paul Westcott to support arguments with restricted values. Thanks,
Paul! And, as if that weren't enough, Adis
Delalic contributed a UML diagram to describe how the CLP
is built. Wow.
And as if that weren't enough,
Keith Brown
ported the command line parser to VS.NET.
Thanks, Keith!
I've seen lots of interest lately in expando objects, e.g. objects that can add
methods and properties on the fly. Joe Graf wrote
a piece on IDispatchEx in MIND that was pretty interesting.
My own implementation of IDispatchEx is available here. It supports
expando objects that have no static properties or methods as well as those that
do. Check out the DispExTest.js for a demonstration, dispeximpl.h,
dynamemlist.h and dynamemlist.cpp for the implementation and MyExpando.h for
the usage.
CComBool is a class to prevent the misuse of the VARIANT_BOOL type.
VARIANT_BOOL is a problem because its legal values are -1 and 0 instead of 1
and 0, making converting back and forth between bool, BOOL and VARIANT_BOOL
problematic. CComBool supports the constructors and operators needed to convert
between the three C++ Windows Boolean types. It also supports operator& and
CopyTo for common COM client and server usage. CComBool is
available here.
The following table lists the various prices you pay for using the CRT and the
default Win98 support in VC6. The builds were done with VC6, SP3, ATL COM
in-proc server, no classes, no MFC, no merged p/s:
|
Target
|
CRT
|
Win98
|
Size
|
|
RelMinSize
|
_ATL_MIN_CRT
|
yes
|
24KB
|
|
RelMinDepend
|
_ATL_MIN_CRT
|
yes
|
24KB
|
|
RelMinSize
|
_ATL_MIN_CRT
|
/opt:nowin98*
|
7KB
|
|
RelMinDepend
|
_ATL_MIN_CRT
|
/opt:nowin98
|
10KB
|
|
RelMinSize
|
MSVCRT
|
/opt:nowin98
|
20KB
|
|
RelMinDepend
|
MSVCRT
|
/opt:nowin98
|
22KB
|
*Note: /opt:nowin98 is a VC6 linker switch that says not to align binaries on a
Win98-friendly boundary. /opt:nowin98 builds will still load and run under
Win98 without a problem, but the loading time could be longer. Also, when
images get above 24KB, the /opt:nowin98 seems not to much of an affect on the
size of the image.
Dharma Shukla and I wrote
"Extending ATL3.0 Containment to Help You Write Real-World Containers" in
the 12/99 issue of MSJ detailing how to add much-needed features to ATL's
support for control containment. Dharma wrote the sample code that accompanies
the piece and has already made improvements to the code based on feedback. He's
maintaining the history and bits
here.
Attila stands for "ATL for Applications." Attila is a set of extensions built
on top of ATL to provide application-level services in the same flavor as MFC.
Towards that end, Attila uses a lot of the same notions as ATL, e.g. heavy use
of templates, static binding and reliance on the compiler and the linker doing
their job. Also, in the flavor of ATL, Attila is under-documented and
requires a lot of user investment to make use of it. However, once you do, we
think you'll find the flexibility and efficiency worth it. If you don't, you
haven't lost much, 'cuz Attila is free. Enjoy.
The Simple Object II ATL ObjectWizard Extension (whew -- I've got to come up
with a shorter name...) provides the following features:
-
Support for [oleautomation] interfaces.
-
Support for the Neutral-threaded apartment.
-
Support for IDispatch-based interfaces other than duals.
-
Better support for disabling features that do not make sense together, e.g. FTM
+ ThreadingModel=Apartment.
-
Updated pop-up help.
Originally, SimpleObject2 was built to do away with the one benefit of
IDispatchImpl over IDelegatingDispImpl -- wizard support. As do most
things developed under the greedy eye of my colleagues, it grew
to support a few more features than that. It's available for download
here. Enjoy.
I got tired of not having a smart type for SAFEARRAYs, so I built one. It's
limited to one dimension (does anyone use multi-dimentional SAFEARRAYs?) and
provides one class for the SAFEARRAY and another for the data itself (the lock
is a resource, too), but the usage is pretty nifty. See comvector.h
for the what and the how.
Also, Ron Jacobs sent me an ATL port of COleSafeArray called CComSafeArray that
I've made available here.
This zip provides two classes for use with dates
and times under Windows:
- CComDATE: Wraps the COM DATE type, providing conversions from VARIANT,
DATE, ANSI string, UNICODE string, time_t, SYSTEMTIME, FILETIME, DOS time
and DBTIMESTAMP data types.
- CComSpan: Represents the result of subtracting one CComDATE from
another. Useful for time/date math.
If you'd like to know about how to expose multiple IDispatch
implementations from a single COM object, check out
this extensive treatment of that very topic.
At atlmdi.zip, please find Charles Petzold's famous
raw Win32 MDI application, MDIDemo, ported to ATL. See atlmdi.h for a set of
base classes for building MDI applications in ATL and mdidemo.cpp for an
example of their use.
Are you getting this: "Error: object doesn't support this property or method"
when you try to call a method on your ATL HTML Control exposed external
dispatch (accessed via window.external in the HTML of the control)? Did it used
to work with IE4 and now it doesn't with IE5? That's because the ATL boys
played fast and loose with the identity laws of COM and, while it took the COM
police a while to catch up with them, catch up with them they did.
Download WrapperDispatch.h for an explanation
of the problem and my solution to it.
TraceHook is a member function call tracing delegator hook based on
Keith Brown's most excellent universal delegator. It allows you to
write:
// Get a COM object to wrap
CComPtr<ICalc> spCalc;
spCalc.CoCreateInstance(CLSID_Calc);
// Wrap it (when _DEBUG is defined only)
TRACEHOOK(OLESTR("MyCalc"), &spCalc.p);
// Use it
spCalc->put_Sum(0);
spCalc->Add(2);
spCalc->Add(2);
long nSum;
spCalc->get_Sum(&nSum);
and see the following in the debug output (with no changes to the object's
source) :
MyCalc, ICalc::put_Sum(0)
MyCalc, ICalc::Add(2)
MyCalc, ICalc::Add(2)
MyCalc, ICalc::get_Sum()
Notice that the call stack is now dumped (for duals, either directly or via
IDispatch, or any method with automation-compliant data types, thanks to
features added by the most excellent Simon Fell!
He also added the ability to hook objects created in scripting environments (or
VB or Java, too), e.g.
' WSH Test script for CalcSvr / TraceHook
' Create the implementation of ITraceHookFactory
set th = CreateObject("UDTraceHookSvr.TraceHook")
' Create an object (an <object> tag in HTML would be fine, too)
set calc = CreateObject("CalcSvr.Calc")
' Trace all further calls on calc
th.ComTrace "MyCalc", calc
calc.sum = 0
calc.add 2
calc.add 2
msgbox "2+2= " & calc.sum
would yield the following debug output:
MyCalc, IDispatch::(Invoke) sum(0)
MyCalc, IDispatch::(Invoke) add(2)
MyCalc, IDispatch::(Invoke) add(2)
MyCalc, IDispatch::(Invoke) sum() returned 4
The source, pre-built binaries and client-side headers are available
here. The pre-built binaries include Keith's delegator as well.
If you've ever had to write the code to pull the ASP intrinsic objects from the
MTS context, you might appreciate CAspPtr, which allows the following:
STDMETHODIMP CJon::DoIt() {
CAspPtr<IResponse> spResponse;
if( spResponse ) {
spResponse->Write(CComVariant(OLESTR("Baby got <b><i>Response</i></b>.")));
}
return S_OK;
}
CAspPtr is available here and was inspired by
Jon Flanders. Thanks, Jon!
Visual Basic and its variants (sic) use IEnumVARIANT to implement the For-Each
statement. Unfortunately, they only ask for 1 element at a time, leading to
terrible performance across apartments. I propose two solutions. One allows you
to wrap any collection in a CollectionBuffer object and set the buffering
yourself, e.g.
Dim collBuffer As Object
Set collBuffer = CreateObject("SmartEnumSvr.CollectionBuffer")
collBuffer.Collection = coll ' coll is an interface on any collection
collBuffer.BufferSize = 1024 ' How many items would you like buffered?
c = 0
For Each v In collBuffer ' Uses SmartEnumVARIANT to buffer items
c = c + 1
Next v
MsgBox "Counted " & c
The second solution allows you to leverage SmartEnumVARIANT on the server-side,
seamlessly to the client. A detailed explanation and code
is available here.
Not too long ago, Jonathan Borden, jborden@MEDIAONE.NET,
posted a nifty class called IMarshalByValueImpl that
implemented IMarshal for objects interested in being marshaled by value . It
was built in the ATL style, i.e. it used fun template tricks, and depended on
the COM class also implementing either IPersistStream or IPersistStreamImpl.
And, in fact, ATL provides an implementation of IPersistStreamInit called
IPersistStreamInitImpl. However, IPersistStreamInitImpl has one fatal flaw: it
implements GetSizeMax by returning E_NOTIMPL. This breaks Jonathan's
IMarshalByValueImpl, which depends on a sane implementation of GetSizeMax from
the class.
IPersistStreamInitImpl2 leverages the property map of
ATL's IPersistStreamInitImpl to build GetSizeMax. The code is not pretty. It's
just pieced together from ATL's implementation of IPersistStreamInit::Save and
CComVariant::WriteToStream, but it seems to work (thanks to Dharma Shukla,
v-dharsh@microsoft.com, for testing it!).
Here's the usage for giving a class MBV:
class PassByValue :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<PassByValue, &CLSID_PassByValue>,
public IDispatchImpl<IPassByValue, &IID_IPassByValue>,
public IMarshalByValueImpl<PassByValue>,
public IPersistStreamInitImpl2<PassByValue>
{
public:
BEGIN_COM_MAP(PassByValue)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IPassByValue)
COM_INTERFACE_ENTRY(IMarshal)
// Don't need to expose these to the world
//COM_INTERFACE_ENTRY(IPersist)
//COM_INTERFACE_ENTRY
(IPersistStreamInit)
END_COM_MAP()
BEGIN_PROP_MAP(PassByValue)
// List of properties to marshal-by-value
...
END_PROP_MAP()
// IPassByValue methods
...
private:
// Whatever data members you wish to marshal
...
public:
BOOL m_bRequiresSave; // Required by IPersistStreamInitImpl2
};
There are three kinds of ways to declare a dispatch-based interface in IDL, but
ATL (as of version 3.0), only supports the implementation of 1.5 of them (duals
and a raw dispinterfaces for handling events). The
ATL Dispatch Sampledemonstrations the use of three ATL-based classes,
one for implementing each type of dispatch-based interface. The header file
that defines these classes, dispimpl2.h, is provided
for use in your own projects.
BTW, thanks to Ehab Kashkash for making this code work under VS.NET as
well as VC6.
If you're into COM Monikers, here's one that I like.
Wish there was a moniker that did CoCreateInstance just like the Class Moniker
calls CoGetClassObject? Wish you were able to compose the Class Moniker with a
host name? Then you'll want the BasicMonikers
project, which bundles together the New moniker and the Host moniker.
Sample syntax follows:
dm.newmk.1:Excel.Application
dm.newmk.1:00024500-0000-0000-C000-000000000046:
dm.hostmk.1:frodo:!dm.newmk.1:00024500-0000-0000-C000-000000000046:
dm.hostmk.1:frodo:!clsid:00024500-0000-0000-C000-000000000046:
regsvr.reg is a regedit script file that adds Register
COM Server and Unregister COM Server to the context menu for DLLs, OCXs and
EXEs under Win95+ and NT4+. In addition, it's also been updated to add Register
TypeLib and Unregister TypeLib commands to .tlb, .odl, .dll, .ocx and .exe
files, using VC6's new regtlib tool.
I've developed a set of macros to support implementing interfaces using nested
composition in ATL (the one common way of implementing interfaces they
neglected). The benefit of composition is that it is easy to implement multiple
interfaces with methods with the same name but that require different behavior,
e.g.
interface IArtist : IUnknown {
HRESULT Draw();
}
interface ICowboy : IUnknown {
HRESULT Draw();
}
The benefit of this particular implementation is that it has no object size
overhead. Interfaces implemented using nested composition have no greater
overhead than using multiple-inheritance. Feel free to
download atlcompose.h for your own use.
Have you ever been jealous of the VB programmer who could write this:
sub EnumVariants(col as Collection)
dim v as variant for each v in col
' Do something with v
next v
end sub
If so, you may be interested in the STL-style IEnumXxx
iterator I've built. You'll also need a supporting file,
atlcopies.h.
githelp.hdefines a set of wrappers for implementing
inter-thread marshaling using the GIT instead of streams. githelp.cpp
provides the non-inline implementation. For another spin on GIT usage, check
out Don Box's GitLip.
Links
I've moved the links section to its own section.