22553053ff
Only scanning has been implemented so far. The most work was really just understanding WinRT well enough to get to this point.
83 lines
3.1 KiB
Go
83 lines
3.1 KiB
Go
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 it’s 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
|
||
}
|