The part I'm not sure about yet is how we notify the first process that their object is now shared. My most sane thought for doing this (I have plenty of others :) is adding a more generic mechanism to tell the client "I have a message for you", but both SIGUSR1 and 2 are both being used. The handler for SIGUSR1 could be modified so that it first asks the server what the message is, which may be a "suspend thread" or "migrate object to server." So before proceeding, I would like to know your preference on how this should be handled.
FWIW, in our discussion on #winehackers, I was assuming you'd do the equivalent of InterlockedExchange in shared memory (between wineserver and the client) that contains the object state. The client would notice as soon as it tried to do anything with the object that the object was moved to the server, and the server would know the previous state from the result of InterlockedExchange. (This assumes every valid object state, including a state indicating that it's in the server, can fit in 64 bits.)
I'm not sure it's a good idea for the wineserver to have to wait on code in a windows process (which, if the process is really hosed, might never respond) before it can reply to a DuplicateHandle request.
The only time you'd need to signal the client is when a thread is waiting on the object being moved, so that the thread can restart the wait using the server. I don't know how you plan to wait on process-local objects, but perhaps you can perform the wait in such a way that the server can interrupt it easily, without disturbing the thread if it's doing anything else?