Basic operations
Tags: excel, automation, python, com
Published: 2022-10-30 14:41:39

Let's dive into the basic operations...

## Dispatch methods
A COM object can be created in various ways:
1. `win32com.client.Dispatch`
1. `win32com.client.DispatchEx`
1. `win32com.client.DispatchWithEvents`
1. `win32com.client.dynamic.Dispatch`
1. `win32com.client.gencache.EnsureDispatch`


### 1. `win32com.client.Dispatch`
This is the **most common** way to start an instance of a COM object.
It tries to automatically detect and use the best dispatching method (early or late binding). 
In fact, behind the scenes, this method uses `dynamic.Dispatch` or `gencache.EnsureDispatch`. The order in which the dispatch types are tested is the following (the first valid dispatch is returned):
1. **Early binding** (also called "Static Dispatch") if possible
1. **Late binding** (also called "Dynamic Dispatch") otherwise

```python
from win32com import client

excel = client.Dispatch('Excel.Application')
```


### 2. `win32com.client.DispatchEx`
Same as `win32com.client.Dispatch`, but allows to create a DCOM object on a **remote machine**.

For example, in the following code snippet, we will open Excel on the server with IP _192.168.1.17_:
```python
from win32com import client

server_name = "192.168.1.17"
excel = client.DispatchEx('Excel.Application', server_name)
```


### 3. `win32com.client.DispatchWithEvents`
Same as `win32com.client.Dispatch`, but allows to respond to **events triggered by the application**.

For example, in the following code a message will be printed on screen every time a user performs a _double click_ on a cell:
```python
from win32com import client

class ExcelEvents:
    def BeforeDoubleClick (self, Target, Cancel):
        print("A double click has occurred")

excel = client.DispatchWithEvents('Excel.Application', ExcelEvents)
```


### 4. `win32com.client.dynamic.Dispatch`
This method completely bypasses the COM cache, directly querying the object instead. [It can solve some problems with the cache](https://groups.google.com/g/xsi_list/c/NSV-e-thdtY/m/d9Vp49sZAzUJ), but it is slower and is subject to application rules (for example in Excel everything is case insensitive, so `excel.VISIBLE` is equal to `excel.Visible`) but it can 
```python
from win32com import client

excel = client.dynamic.Dispatch('Excel.Application')
```

**PRO:**
- _Case insensitive_ lookup

**CONS:**
- _Slower_ than `gencache.EnsureDispatch`

### 5. `win32com.client.gencache.EnsureDispatch`
This method forces the use/creation of the cache.

The cache can be found inside the folder: `C:\Users\{USERNAME}\AppData\Local\Temp\gen_py`
```python
from win32com import client

excel = client.gencache.EnsureDispatch('Excel.Application')
```

#### Known bugs
Using this method you might encounter [some bugs](https://stackoverflow.com/a/51993953/8965861) involving the cache, like the infamous `AttributeError: 'module' object has no attribute 'CLSIDToPackageMap'`.
 
This problem in particular can be solved in two ways:
1. [deleting](https://stackoverflow.com/a/66910869/8965861) the cache folder (`%TEMP%/gen_py`) so that the next call to `EnsureDispatch` will trigger a cache refresh;
1. forcing a [cache refresh](https://stackoverflow.com/a/66910869/8965861) yourself;

Then all you need to do is running again the `client.gencache.EnsureDispatch` function and you'll be good to go!


**PRO:**
- _Faster_ than `dynamic.Dispatch` thanks to the cache

**CONS:**
- More subject to _errors_ (most notably the `AttributeError` cited before) caused by the cache