Skip to content

Commit

Permalink
Added second example to README
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaSjoding committed Mar 8, 2019
1 parent 2a405b0 commit 77b0236
Showing 1 changed file with 73 additions and 4 deletions.
77 changes: 73 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ thread to be initialized, otherwise COM-allocated resources may be released
prematurely. This poses a challenge in Go, which can have many goroutines
running in parallel with weak thread affinity.

The comshim package provides a solution to this problem by maintaining
The `comshim` package provides a solution to this problem by maintaining
a single thread-locked goroutine that has been initialized for
multi-threaded COM use via a call to CoIntializeEx. A reference counter is
multi-threaded COM use via a call to `CoIntializeEx`. A reference counter is
used to determine the ongoing need for the shim to stay in place. Once the
counter reaches 0, the thread is released and COM may be deinitialized.

The comshim package is designed to allow COM-based libraries to hide the
threading requirements of COM from the user. COM interfaces can be hidden
behind idomatic Go structures that increment the counter with calls to
NewType() and decrement the counter with calls to Type.Close(). To see
`NewType()` and decrement the counter with calls to `Type.Close()`. To see
how this is done, take a look at the WrapperUsage example.

Example Usage
Global Example
====

```
Expand All @@ -39,4 +39,73 @@ func main() {
// Do COM things here
}
```

Wrapper Example
====

```
package main
import (
"sync"
"github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
"github.com/scjalliance/comshim"
)
// Object wraps a COM interface in a way that is safe for multi-threaded access.
// In this example it wraps IUnknown.
type Object struct {
m sync.Mutex
iface *ole.IUnknown
}
// NewObject creates a new object. Be sure to document the need to call Close().
func NewObject() (*Object, error) {
comshim.Add(1)
iunknown, err := oleutil.CreateObject("Excel.Application")
if err != nil {
comshim.Done()
return nil, err
}
return &Object{iface: iunknown}, nil
}
// Close releases any resources used by the object.
func (o *Object) Close() {
o.m.Lock()
defer o.m.Unlock()
if o.iface == nil {
return // Already closed
}
o.iface.Release()
o.iface = nil
comshim.Done()
}
// Foo performs some action using the object's COM interface.
func (o *Object) Foo() {
o.m.Lock()
defer o.m.Unlock()
// Make use of o.iface
}
func main() {
obj1, err := NewObject() // Create an object
if err != nil {
panic(err)
}
defer obj1.Close() // Be sure to close the object when finished
obj2, err := NewObject() // Create a second object
if err != nil {
panic(err)
}
defer obj2.Close() // Be sure to close it too
// Work with obj1 and obj2
}
```

0 comments on commit 77b0236

Please sign in to comment.