prototooth/winbt/event.go
Ayke van Laethem 22553053ff Add initial Windows support
Only scanning has been implemented so far. The most work was really just
understanding WinRT well enough to get to this point.
2020-05-30 21:51:27 +02:00

83 lines
3.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package winbt
// This file implements a COM object that can be used for various event
// callbacks. In C++, it would use an ITypedEventHandler instantiation.
import (
"unsafe"
"github.com/go-ole/go-ole"
)
// const void * winbt_getEventVtbl(void);
import "C"
// Event implements event handler interfaces (ITypedEventHandler). This is
// therefore a valid COM object, derived from IUnknown.
type Event struct {
ole.IUnknown
IID *ole.GUID
Callback func(*Event, *ole.IInspectable)
token uintptr
}
// NewEvent creates a new COM object for event callbacks. The IID must be the
// IID for a particular event, which is unfortunately not included in the *.idl
// files but has to be found in the relevant C++/WinRT header files.
func NewEvent(iid *ole.GUID, callback func(*Event, *ole.IInspectable)) *Event {
// Another way to find the IID is to print the requested IID in the
// QueryInterface method below. The first queried IID is likely the one
// that is the event interface IID.
// The event must be allocated on the C heap, because it is not allowed to
// retain a pointer on the Go heap after a non-Go call returns (e.g.
// syscall.Syscall).
event := (*Event)(C.malloc(C.size_t(unsafe.Sizeof(Event{}))))
event.RawVTable = (*interface{})(C.winbt_getEventVtbl())
event.IID = iid
event.Callback = callback
return event
}
// The two functions below implement IUnknown and an interface I couldn't
// really get the definition of (possibly ITypedEventHandler, although
// ITypedEventHandler is really a C++ template). The closest thing I could find
// to documentation are the C++/WinRT headers and this mention by Kenny Kerr
// (the original developer of C++/WinRT):
// https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/august/windows-with-c-the-windows-runtime-application-model
// > [...] Fortunately, all of these interfaces are generated by the MIDL
// > compiler, which takes care to specialize each one, and its on these
// > specializations that it attaches the GUID representing the interface
// > identifier. As complicated as the previous typedef might appear, it
// > defines a COM interface that derives directly from IUnknown and provides
// > a single method called Invoke.
//export winbt_Event_QueryInterface
func winbt_Event_QueryInterface(eventPtr, iidPtr unsafe.Pointer, ppvObject *unsafe.Pointer) uintptr {
// This function must adhere to the QueryInterface defined here:
// https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nn-unknwn-iunknown
iid := (*ole.GUID)(iidPtr)
event := (*Event)(eventPtr)
if ole.IsEqualGUID(iid, event.IID) {
// This is us.
*ppvObject = eventPtr
return ole.S_OK
}
if ole.IsEqualGUID(iid, ole.IID_IUnknown) {
// This is our parent. There are some limitations as to what we can
// return here, but returning the *Event pointer is fine.
*ppvObject = eventPtr
return ole.S_OK
}
return 0x80004002 // E_NOTINTERFACE
}
//export winbt_Event_Invoke
func winbt_Event_Invoke(eventPtr, senderPtr, argsPtr unsafe.Pointer) uintptr {
// See the quote above.
event := (*Event)(eventPtr)
argsInspectable := (*ole.IInspectable)(argsPtr)
event.Callback(event, argsInspectable)
return ole.S_OK
}