If I attach a file to an existing completion port, do I have to close the completion port handle a second time?

There are two ways of calling
the
Create­IO­Completion­Port function.
You can pass a null pointer as the
Existing­Completion­Port parameter,
indicating that you would like to create a brand new completion port,
associated with the file handle you passed (if you passed one).
Or you can pass the handle of an existing completion port,
and the file handle you passed will be associated with that port,
in addition to whatever other file handles are already associated
with that port.

In both cases, the return value on success is a handle to the I/O
completion port,
either the brand new one or the existing one.
The question from a customer was,
"In the case where I am associating a file handle to an existing
completion port,
do I need to close the completion port handle a second time?"
In other words, is there a handle leak in this code:

No, there is no handle leak.
If you ask to associate a file with an existing completion port,
the same handle you passed as the
Existing­Completion­Port parameter
is returned back on success.
There is no new obligation to close the handle a second time
because
kernel handles are not reference-counted.
Closing a kernel handle twice is always an error,
because the first close closes the handle,
and the second close attempts to use a handle that is already closed.
There is no reference count on handles.¹

¹ There is a reference count on kernel objects, but handles are not
reference-counted.
The standard way to increment the reference count on a kernel object is...
to create a new handle to it!

A handle is always a reference by definition (hence its name: something used to "grab" an object). IIRC, in the early versions of classic Mac OS, handles were actually indexes into a table that contained (pointer, reference count) pairs. Of course, documentation warned to manage them as opaque values, but in later versions (7.x and newer) many compatibility problems were caused by applications and extensions that tried to be too clever. Does it sound familiar? ;-)

In my ignorance of what the a "completion port" is or does I checked out the classical "topic introduction page" in the Platform SDK (msdn.microsoft.com/…/aa365198), which usually does a decent job at explaining what are we talking about. What I found is something along the lines of the CardSpace stuff – generic description with vagues hints of context ("provide an efficient threading model for processing multiple asynchronous I/O requests on a multiprocessor system") and detailed descriptions for people who already know what we are talking about.

Matteo: An I/O Completion Port is a queue of I/O completion packets. Once an asynchronous file handle is associated with a completion port, then whenever an I/O completes on that file, a completion packet is posted to the queue. The queued packets are consumed by calling GetQueuedCompletionStatus.

Generally you will have a single IOCP to handle all the I/O in your process and a pool of threads that all call GetQueuedCompletionStatus in a loop. This allows asyncrhonous I/O to be handled as efficiently as possible, with a minimum of kernel mode transitions and context switches.

'kernel handles are not referenced-counted' – is it STRICTLY TRUE? IMHO better answer 'no' for both types on questions – 'Are kernel object handles are reference-counted?' and 'Are kernel object handles are NOT reference counted?'. The second type of question can raise if somebody will wish to rely on fact that for example DuplicateHandle always generates new unique handle value, even it has completely matches properties as initial one.

I had a dream last night that Raymond made some particular outlandish response to somebody's comment on tomorrows post, and for some reason I called him on his phone (never mind how I had his number) to explain it rather than post a reply.