The function EnsureDispatch() in win32.client.gencache allows you specify a prog_id and the gen_py cache wrapper objects are created at runtime if they don't already exists. This is useful if you don't care what version of COM server you use, allowing users to have various versions and still work with your code.

First the gencache code must be allowed to create the cache by setting win32com.gencache.is_readonly = False. Then as the target machine may not have Python installed it is necessary to get the gencache code to use a suitable directory other than the default in lib\site-packages\win32com\client\gen_py. This is achieved by simply removing (or renaming) win32com\client\gen_py and the gen_py cache is then created in %temp% (user's temp)

A final wrinkle is that the first time you run it the cache is created but an import exception is generated. It appears that py2exe never calls the win32com.client.__init__() in the 'import win32com.client'. This code creates the cache __init__.py file that sets the package module path. A call to gencache.Rebuild()}} fixes that as calling {{{__init__() doesn't seem to work either.

For example:

   1 import win32com.client
   2 if win32com.client.gencache.is_readonly == True:
   3 
   4     #allow gencache to create the cached wrapper objects
   5     win32com.client.gencache.is_readonly = False
   6 
   7     # under p2exe the call in gencache to __init__() does not happen
   8     # so we use Rebuild() to force the creation of the gen_py folder
   9     win32com.client.gencache.Rebuild()
  10 
  11     # NB You must ensure that the python...\win32com.client.gen_py dir does not exist
  12     # to allow creation of the cache in %temp%
  13 
  14 # Use SAPI speech through IDispatch
  15 voice = EnsureDispatch("Sapi.SpVoice", bForDemand=0)
  16 voice.Speak( "Hello World." )