Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add documentation and make structures and documentation available out…
…side of Windows.
  • Loading branch information
Jacob Santos committed May 13, 2015
1 parent 172a39f commit 10ae246
Show file tree
Hide file tree
Showing 15 changed files with 260 additions and 140 deletions.
51 changes: 51 additions & 0 deletions error.go
@@ -0,0 +1,51 @@
package ole

// OleError stores COM errors.
type OleError struct {
hr uintptr
description string
subError error
}

// NewError creates new error with HResult.
func NewError(hr uintptr) *OleError {
return &OleError{hr: hr}
}

// NewErrorWithDescription creates new COM error with HResult and description.
func NewErrorWithDescription(hr uintptr, description string) *OleError {
return &OleError{hr: hr, description: description}
}

// NewErrorWithSubError creates new COM error with parent error.
func NewErrorWithSubError(hr uintptr, description string, err error) *OleError {
return &OleError{hr: hr, description: description, subError: err}
}

// Code is the HResult.
func (v *OleError) Code() uintptr {
return uintptr(v.hr)
}

// String description, either manually set or format message with error code.
func (v *OleError) String() string {
if v.description != "" {
return errstr(int(v.hr)) + " (" + v.description + ")"
}
return errstr(int(v.hr))
}

// Error implements error interface.
func (v *OleError) Error() string {
return v.String()
}

// Description retrieves error summary, if there is one.
func (v *OleError) Description() string {
return v.description
}

// SubError returns parent error, if there is one.
func (v *OleError) SubError() error {
return v.subError
}
7 changes: 7 additions & 0 deletions error_func.go
@@ -0,0 +1,7 @@
// +build !windows

package ole

func errstr(errno int) string {
return ""
}
23 changes: 23 additions & 0 deletions error_windows.go
@@ -0,0 +1,23 @@
// +build windows

package ole

import (
"fmt"
"syscall"
"unicode/utf16"
)

func errstr(errno int) string {
// ask windows for the remaining errors
var flags uint32 = syscall.FORMAT_MESSAGE_FROM_SYSTEM | syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY | syscall.FORMAT_MESSAGE_IGNORE_INSERTS
b := make([]uint16, 300)
n, err := syscall.FormatMessage(flags, 0, uint32(errno), 0, b, nil)
if err != nil {
return fmt.Sprintf("error %d (FormatMessage failed with: %v)", errno, err)
}
// trim terminating \r and \n
for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- {
}
return string(utf16.Decode(b[:n]))
}
52 changes: 52 additions & 0 deletions guid.go
@@ -0,0 +1,52 @@
package ole

var (
// NullInterfaceID is null Interface ID, used when no other Interface ID is known.
IID_NULL = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}

// IUnknownInterfaceID is for IUnknown interfaces.
IID_IUnknown = &GUID{0x00000000, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}

// IDispatchInterfaceID is for IDispatch interfaces.
IID_IDispatch = &GUID{0x00020400, 0x0000, 0x0000, [8]byte{0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}

// IConnectionPointContainerInterfaceID is for IConnectionPointContainer interfaces.
IID_IConnectionPointContainer = &GUID{0xB196B284, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}

// IConnectionPointInterfaceID is for IConnectionPoint interfaces.
IID_IConnectionPoint = &GUID{0xB196B286, 0xBAB4, 0x101A, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}

// IInspectableInterfaceID is for IInspectable interfaces.
IID_IInspectable = &GUID{0xaf86e2e0, 0xb12d, 0x4c6a, [8]byte{0x9c, 0x5a, 0xd7, 0xaa, 0x65, 0x10, 0x1e, 0x90}}

// IProvideClassInfoInterfaceID is for IProvideClassInfo interfaces.
IID_IProvideClassInfo = &GUID{0xb196b283, 0xbab4, 0x101a, [8]byte{0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}}
)

// GUID is Windows API specific GUID type.
//
// This exists to match Windows GUID type for direct passing for COM.
// Format is in xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx.
type GUID struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}

// IsEqualGUID compares two GUID.
//
// Not constant time comparison.
func IsEqualGUID(guid1 *GUID, guid2 *GUID) bool {
return guid1.Data1 == guid2.Data1 &&
guid1.Data2 == guid2.Data2 &&
guid1.Data3 == guid2.Data3 &&
guid1.Data4[0] == guid2.Data4[0] &&
guid1.Data4[1] == guid2.Data4[1] &&
guid1.Data4[2] == guid2.Data4[2] &&
guid1.Data4[3] == guid2.Data4[3] &&
guid1.Data4[4] == guid2.Data4[4] &&
guid1.Data4[5] == guid2.Data4[5] &&
guid1.Data4[6] == guid2.Data4[6] &&
guid1.Data4[7] == guid2.Data4[7]
}
49 changes: 5 additions & 44 deletions iunknown.go
@@ -1,11 +1,6 @@
// +build windows

package ole

import (
"syscall"
"unsafe"
)
import "unsafe"

type IUnknown struct {
RawVTable *interface{}
Expand All @@ -27,14 +22,13 @@ func (v *IUnknown) VTable() *IUnknownVtbl {
return (*IUnknownVtbl)(unsafe.Pointer(v.RawVTable))
}

func (v *IUnknown) QueryInterface(iid *GUID) (disp *IDispatch, err error) {
disp, err = queryInterface(v, iid)
return
func (v *IUnknown) QueryInterface(iid *GUID) (*IDispatch, error) {
return queryInterface(v, iid)
}

func (v *IUnknown) MustQueryInterface(iid *GUID) (disp *IDispatch) {
func (v *IUnknown) MustQueryInterface(iid *GUID) *IDispatch {

This comment has been minimized.

Copy link
@noblehng

noblehng May 15, 2015

this change make the variable disp in the following line undefined and the code won't compile anymore.

disp, _ = queryInterface(v, iid)
return
return disp
}

func (v *IUnknown) AddRef() int32 {
Expand All @@ -44,36 +38,3 @@ func (v *IUnknown) AddRef() int32 {
func (v *IUnknown) Release() int32 {
return release(v)
}

func queryInterface(unk *IUnknown, iid *GUID) (disp *IDispatch, err error) {
hr, _, _ := syscall.Syscall(
unk.VTable().QueryInterface,
3,
uintptr(unsafe.Pointer(unk)),
uintptr(unsafe.Pointer(iid)),
uintptr(unsafe.Pointer(&disp)))
if hr != 0 {
err = NewError(hr)
}
return
}

func addRef(unk *IUnknown) int32 {
ret, _, _ := syscall.Syscall(
unk.VTable().AddRef,
1,
uintptr(unsafe.Pointer(unk)),
0,
0)
return int32(ret)
}

func release(unk *IUnknown) int32 {
ret, _, _ := syscall.Syscall(
unk.VTable().Release,
1,
uintptr(unsafe.Pointer(unk)),
0,
0)
return int32(ret)
}
15 changes: 15 additions & 0 deletions iunknown_func.go
@@ -0,0 +1,15 @@
// +build !windows

package ole

func queryInterface(unk *IUnknown, iid *GUID) (disp *IDispatch, err error) {
return nil, NewError(E_NOTIMPL)
}

func addRef(unk *IUnknown) int32 {
return 0
}

func release(unk *IUnknown) int32 {
return 0
}
41 changes: 41 additions & 0 deletions iunknown_windows.go
@@ -0,0 +1,41 @@
// +build windows

package ole

import (
"syscall"
"unsafe"
)

func queryInterface(unk *IUnknown, iid *GUID) (disp *IDispatch, err error) {
hr, _, _ := syscall.Syscall(
unk.VTable().QueryInterface,
3,
uintptr(unsafe.Pointer(unk)),
uintptr(unsafe.Pointer(iid)),
uintptr(unsafe.Pointer(&disp)))
if hr != 0 {
err = NewError(hr)
}
return
}

func addRef(unk *IUnknown) int32 {
ret, _, _ := syscall.Syscall(
unk.VTable().AddRef,
1,
uintptr(unsafe.Pointer(unk)),
0,
0)
return int32(ret)
}

func release(unk *IUnknown) int32 {
ret, _, _ := syscall.Syscall(
unk.VTable().Release,
1,
uintptr(unsafe.Pointer(unk)),
0,
0)
return int32(ret)
}

0 comments on commit 10ae246

Please sign in to comment.