mscom

package
v0.0.0-...-2f48622 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 20, 2024 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package mscom implements COM(The Microsoft Component Object Model) object creation and invocation.

A COM interface is a struct contains a virtual function table(VMT) pointer. A VMT is a struct of MethodPtr(s). Neither the interface nor the VMT should contain go pointer practically, because they usually are handed out to C code(or the COM library). Allocating them using Alloc/AllocMem in this package or HeapAlloc like APIs.

For creating a COM object, call Init() on the VTM and then create methods use the *MethodCreator returned. CAUTION: Do not use the order of method in microsoft website, which may be reordered there!!

For using a COM object, invoke Call on the MethodPtr(s) in VTM.

If customized reference counting is not required, InitIUnknownImpl can be used as a helper to create COM objects. See CreateIUnknownImpl and other examples.

See type IUnknown and IMalloc for details.

Index

Examples

Constants

This section is empty.

Variables

View Source
var IID_IUnknown = gg.Must(sys.UuidFromStringW("00000000-0000-0000-C000-000000000046"))

Functions

func Alloc

func Alloc[T any]() *T

Alloc allocates a chunk of memory large enough to hold a T. Alloc using the OLE memory allocator(CoTaskMem[Alloc/Free]).

https://learn.microsoft.com/en-us/windows/win32/com/the-ole-memory-allocator "Whenever ownership of an allocated chunk of memory is passed through a COM interface or between a client and the COM library, you must use this COM allocator to allocate the memory. Allocation internal to an object can use any allocation scheme desired, but the COM memory allocator is a handy, efficient, and thread-safe allocator."

func AllocMem

func AllocMem(size uintptr) unsafe.Pointer

AllocMem allocates a chunk of memory using the OLE memory allocator.

func Cleanup

func Cleanup[T any](obj *T)

Cleanup is expected to be called when an object is released.

func CreateIUnknownImpl

func CreateIUnknownImpl(ppObject **IUnknown) error

CreateIUnknownImpl creates an object which implements IUnknown interface. This function may also be considered as an example of creating COM objects with InitIUnknownImpl.

func Free

func Free[T any](p *T)

Free frees the memory allocated by Alloc or AllocMem.

func FreeMem

func FreeMem(p unsafe.Pointer)

FreeMem frees the memory allocated by Alloc or AllocMem

Types

type IMalloc

type IMalloc struct {
	// contains filtered or unexported fields
}
Example
package main

import (
	"fmt"
	"unsafe"

	"github.com/mkch/gw/mscom"
	"github.com/mkch/gw/mscom/sys"
)

func main() {
	var malloc *mscom.IMalloc
	if r := sys.CoGetMalloc((*unsafe.Pointer)(unsafe.Pointer(&malloc))); r != sys.S_OK {
		panic(r)
	}
	defer malloc.IUnknown().Release()

	p := malloc.Alloc(5)
	if p == nil {
		panic("out of memory")
	}
	defer malloc.Free(p)

	n := malloc.GetSize(p)
	fmt.Println(n)

}
Output:

5

func (*IMalloc) Alloc

func (m *IMalloc) Alloc(size uintptr) unsafe.Pointer

func (*IMalloc) DidAlloc

func (m *IMalloc) DidAlloc(p unsafe.Pointer) int

func (*IMalloc) Free

func (m *IMalloc) Free(p unsafe.Pointer)

func (*IMalloc) GetSize

func (m *IMalloc) GetSize(p unsafe.Pointer) uintptr

func (*IMalloc) HeapMinimize

func (m *IMalloc) HeapMinimize()

func (*IMalloc) IUnknown

func (m *IMalloc) IUnknown() *IUnknown

func (*IMalloc) Realloc

func (m *IMalloc) Realloc(p unsafe.Pointer, size uintptr) unsafe.Pointer

type IMallocVMT

type IMallocVMT struct {
	IUnknownVMT
	// contains filtered or unexported fields
}

type IUnknown

type IUnknown struct {
	// contains filtered or unexported fields
}

func (*IUnknown) AddRef

func (i *IUnknown) AddRef() uint32

func (*IUnknown) QueryInterface

func (i *IUnknown) QueryInterface(riid sys.REFIID, pp *unsafe.Pointer) error

func (*IUnknown) Release

func (i *IUnknown) Release() uint32

type IUnknownVMT

type IUnknownVMT struct {
	// contains filtered or unexported fields
}

IUnknownVMT is the v-table of IUnknown interface. The doc(microsoft website) may reorder the method list. Refer to C source code to get the correct order.

type MethodCreator

type MethodCreator methods

MethodCreator can be used to create method of COM object.

func Init

func Init[T any](obj *T) *MethodCreator

Init initialize obj and returns the newly created method set.

func InitIUnknownImpl

func InitIUnknownImpl[T any](obj *T, vt *IUnknownVMT, queryInterface func(sys.REFIID, *unsafe.Pointer) sys.HRESULT, release func()) (mtds *MethodCreator)

InitIUnknownImpl initializes an IUnknownVMT with a default implementation.

This function is a helper to implement arbitrary COM object. See CreateIUnknownImpl and other examples.

This implementation implements reference counting by atomic.Int32, and calling release when reference count reaches 0. It implements QueryInterface method for IID_IUnknown after checking param for E_POINTER and then calling queryInterface.

If queryInterface returns S_OK, the reference count is increased by 1 in this func. So don't increase the reference count in queryInterface itself. The returned MethodCreator is the result of calling Init(obj) and can be used to add more methods other than that of IUnknown.

Pitfall when declaring VMT: The method order of COM interface may be reorder in microsoft website!! So refer to the C source code to get the correct order.

Example
package main

import (
	"fmt"
	"unsafe"

	"github.com/mkch/gg"
	"github.com/mkch/gw/mscom"
	"github.com/mkch/gw/mscom/sys"
)

type INetworkListManagerEventsImplVMT struct {
	mscom.IUnknownVMT

	connectivityChanged mscom.MethodPtr
}

type INetworkListManagerEventsImpl struct {
	vt *INetworkListManagerEventsImplVMT
}

func (s *INetworkListManagerEventsImpl) IUnknown() *mscom.IUnknown {
	return (*mscom.IUnknown)(unsafe.Pointer(s))
}

var IID_INetworkListManagerEvents = gg.Must(sys.UuidFromStringW("dcb00001-570f-4a9b-8d69-199fdba5723b"))

func main() {
	var i *INetworkListManagerEventsImpl
	if err := CreateINetworkListManagerEventsImpl(&i); err != nil {
		panic(err)
	}
	defer i.IUnknown().Release()
}

func CreateINetworkListManagerEventsImpl(ppObject **INetworkListManagerEventsImpl) error {
	if ppObject == nil {
		return sys.HResultError(sys.E_POINTER)
	}
	// Alloc the interface and v-table in one block of memory.
	mem := mscom.Alloc[struct {
		INetworkListManagerEventsImpl
		INetworkListManagerEventsImplVMT
	}]()
	// Setup v-table.
	mem.INetworkListManagerEventsImpl.vt = &mem.INetworkListManagerEventsImplVMT
	// Call InitIUnknownImpl to initialize the IUnknownVMT part.
	mscom.InitIUnknownImpl(&mem.INetworkListManagerEventsImpl, &mem.IUnknownVMT, func(id sys.REFIID, p *unsafe.Pointer) sys.HRESULT {
		// This object can be converted to INetworkListManagerEvents interface.
		if *id == *IID_INetworkListManagerEvents {
			*p = unsafe.Pointer(&mem.INetworkListManagerEventsImpl)
			return sys.S_OK
		}
		return sys.E_NOINTERFACE
	}, func() {
		mscom.Free(mem)
	}).
		// Create the ConnectivityChanged method of INetworkListManagerEvents.
		Create(&mem.INetworkListManagerEventsImplVMT.connectivityChanged, func(connectivity uintptr) uintptr {
			fmt.Printf("connectivityChanged: %v\n", connectivity)
			return uintptr(sys.S_OK)
		})

	*ppObject = &mem.INetworkListManagerEventsImpl
	return nil
}
Output:

func (*MethodCreator) Create

func (m *MethodCreator) Create(p *MethodPtr, f any) *MethodCreator

Create creates a method of an COM object. Argument p is the method pointer in v-table. Argument f is the function actually executed when the method is called. Function f is expected to be a function with zero or more uintptr arguments(method receiver must be omitted, we have closures in go) and one uintptr result. The return value is m itself to allow chained calls.

type MethodPtr

type MethodPtr uintptr

MethodPtr is a COM method pointer.

func (MethodPtr) Call

func (p MethodPtr) Call(receiver unsafe.Pointer, a ...uintptr) (r1, r2 uintptr)

Call executes a COM method p with receiver and arguments a. The receiver should not be a go pointer. If it is, pin it using runtime.Pinner.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL