I have created a Direct3D9 wrapper in Go which uses CGo to interface with the COM objects in C.
I would like to get rid of the dependency on a C-compiler under Windows so the user would not have to install MinGW or Cygwin to use DirectX from Go.
The problem is that d3d9.dll does not expose C-functions but uses COM. The only function that can be called directly after loading the DLL (with syscall.LoadLibrary("d3d9.dll")) is Direct3DCreate9. This returns a COM object which exposes all functionality as methods.
How can I call COM object methods in a DLL from pure Go without CGo?
I know of the Go-OLE library which states it calls COM interfaces without CGo but I cannot, from the sources, see how I would go about doing the same thing for Direct3D9. A simple example with only the relevant parts would be of great help.
I asked the guys from go-ole, like #kostix suggested.
Here is the solution:
d3d9 doesn't have generally COM vtbl. for example, it doesn't have
IDispatch interface. So you can't use go-ole for d3d9. But you can do
it with writing all interface in go.
package main
import (
"fmt"
"log"
"syscall"
"unsafe"
)
const (
D3D9_SDK_VERSION = 32
)
var (
libd3d9 = syscall.NewLazyDLL("d3d9.dll")
procDirect3DCreate9 = libd3d9.NewProc("Direct3DCreate9")
)
type IDirect3D struct {
lpVtbl *IDirect3DVtbl
}
type IDirect3DVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
RegisterSoftwareDevice uintptr
GetAdapterCount uintptr
GetAdapterIdentifier uintptr
GetAdapterModeCount uintptr
EnumAdapterModes uintptr
GetAdapterDisplayMode uintptr
CheckDeviceType uintptr
CheckDeviceFormat uintptr
CheckDeviceMultiSampleType uintptr
CheckDepthStencilMatch uintptr
CheckDeviceFormatConversion uintptr
GetDeviceCaps uintptr
GetAdapterMonitor uintptr
CreateDevice uintptr
}
func (v *IDirect3D) AddRef() int32 {
ret, _, _ := syscall.Syscall(
v.lpVtbl.AddRef,
1,
uintptr(unsafe.Pointer(v)),
0,
0)
return int32(ret)
}
func (v *IDirect3D) Release() int32 {
ret, _, _ := syscall.Syscall(
v.lpVtbl.Release,
1,
uintptr(unsafe.Pointer(v)),
0,
0)
return int32(ret)
}
func (v *IDirect3D) GetAdapterCount() uint32 {
ret, _, _ := syscall.Syscall(
v.lpVtbl.GetAdapterCount,
1,
uintptr(unsafe.Pointer(v)),
0,
0)
return uint32(ret)
}
func main() {
v, r, err := procDirect3DCreate9.Call(uintptr(D3D9_SDK_VERSION))
if r != 0 && err != nil {
log.Fatal(err)
}
d3d := *((**IDirect3D)(unsafe.Pointer(&v)))
d3d.AddRef()
defer d3d.Release()
fmt.Println(d3d.GetAdapterCount())
}
(c) mattn
(Not a comprehensive answer as I have no time to actually test this, but still…)
While MSDN most of the time assumes you work with COM objects using some platform which has built-in "glue" for them (such as Visual C++™ product or something like this), in fact it is possible to work with COM objects using plain C—look here and here for starters.
Studying those resources you can learn that calling methods on a "COM interface" amounts to properly working with its "VTBL" (Virtual function TaBLe) block which is always located in a well-known place relative to the pointer disguised by that "interface" "thing" returned by functions instantiating COM objects.
The go-ole package implements in plain Go what you'd otherwise do in plain C, so armed with the knowledge of "to call methods on a COM objects we need to operate on its VTBL" we can find the implementation of IDispatch support in that package. So I'd start there.
I'd also go right into the go-ole issue tracker asking for implementing a piece of example code which would show how to call methods on a COM object's handler acquired by means other than calling functions from go-ole package.
I'm trying to call SHGetImageList in Go in order to extract icons from .EXE files. The problem is that I don't know how to create/pass an "IImageList2 interface" in Go, which is something SHGetImageList requires.
I've tried miscellaneous things for a few hours, but it all results in the same E_NOINTERFACE error. Basically they're all "shots in the dark" ([]byte array to see if I could receive any "data" at all, an actual interface{} in Go containing the same functions as the IImagelist2 interface defined by MSDN, etc). If it is of any relevance, I do have a working version of this in C# using something along the lines of http://www.pinvoke.net/default.aspx/shell32.shgetimagelist, but I simply have no real clue on how to "translate" that to Go. Any help would be much appreciated.
Example Go code below, with some info and links to MSDN in the comments.
package main
import (
"fmt"
"syscall"
"unsafe"
)
var (
shell32 = syscall.MustLoadDLL("shell32.dll")
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx
procSHGetFileInfo = shell32.MustFindProc("SHGetFileInfoW")
//https://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx
procSHGetImageList = shell32.MustFindProc("SHGetImageList")
)
func main() {
someExeFile := `c:\windows\explorer.exe`
iconIndex := GetIconIndex(someExeFile)
// The problem:
HRESULT, _, _ := procSHGetImageList.Call(
uintptr(SHIL_JUMBO),
uintptr(unsafe.Pointer(&IID_IImageList2)),
// I don't know how pass/create an "IImageList interface" in Go,
// or if it's even possible without relying on CGO.
// IImageList interface:
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb761419(v=vs.85).aspx
// Currently there's just a pointer to an empty []byte so that the code will compile.
// HRESULT naturally contains the error code E_NOINTERFACE (2147500034),
// which makes sense seeing as I'm not passing a valid interface.
uintptr(unsafe.Pointer(&[]byte{})),
)
fmt.Println(iconIndex, HRESULT)
}
const SHIL_JUMBO = 0x4
const shGetFileInfoLen = 3
const shGetFileInfoFlags = 16400 //(SysIconIndex|LargeIcon|UseFileAttributes)
// use SHGetFileInfo to get the icon index (only value we care about)
func GetIconIndex(fileName string) int {
buf := make([]uint16, shGetFileInfoLen)
ret, _, _ := procSHGetFileInfo.Call(
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(fileName))),
0,
uintptr(unsafe.Pointer(&buf[0])),
shGetFileInfoLen,
shGetFileInfoFlags,
)
if ret != 0 && buf[2] > 0 {
return int(buf[2])
}
return 0
}
// From: "192B9D83-50FC-457B-90A0-2B82A8B5DAE1"
var IID_IImageList2 = &GUID{0x192b9d83, 0x50fc, 0x457b, [8]byte{0x90, 0xa0, 0x2b, 0x82, 0xa8, 0xb5, 0xda, 0xe1}}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx
type GUID struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}
UPDATE
The problem now is that it's exiting with an error(0xC0000005) when calling the Syscall to get the actual icon pointer.
package main
import (
"fmt"
"syscall"
"unsafe"
)
var (
shell32 = syscall.MustLoadDLL("shell32.dll")
// https://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx
procSHGetFileInfo = shell32.MustFindProc("SHGetFileInfoW")
//https://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx
procSHGetImageList = shell32.MustFindProc("SHGetImageList")
ole32 = syscall.MustLoadDLL("ole32.dll")
procCoInitialize = ole32.MustFindProc("CoInitialize")
)
func main() {
someExeFile := `c:\windows\explorer.exe`
procCoInitialize.Call()
iconIndex := GetIconIndex(someExeFile)
var imglist *IImageList
hr, _, _ := procSHGetImageList.Call(
uintptr(SHIL_JUMBO),
uintptr(unsafe.Pointer(&IID_IImageList)),
uintptr(unsafe.Pointer(&imglist)),
)
// These look OK
fmt.Println(iconIndex, hr, imglist.Vtbl.GetIcon)
var hIcon uintptr
// GetIcon: https://msdn.microsoft.com/en-us/library/windows/desktop/bb761463(v=vs.85).aspx
hr, _, _ = syscall.Syscall(imglist.Vtbl.GetIcon,
uintptr(unsafe.Pointer(imglist)),
uintptr(iconIndex),
getIconFlags,
uintptr(unsafe.Pointer(&hIcon)),
)
// Errors: "Process finished with exit code -1073741819 (0xC0000005)"
fmt.Println("hIcon:", hIcon) // Never reaches this
}
// ILD_TRANSPARENT | ILD_IMAGE
const getIconFlags = 0x00000001 | 0x00000020
const SHIL_JUMBO = 0x4
const shGetFileInfoLen = 3
const shGetFileInfoFlags = 16400 //(SysIconIndex|LargeIcon|UseFileAttributes)
// use SHGetFileInfo to get the icon index (only value we care about)
func GetIconIndex(fileName string) int {
buf := make([]uint16, shGetFileInfoLen)
ret, _, _ := procSHGetFileInfo.Call(
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(fileName))),
0,
uintptr(unsafe.Pointer(&buf[0])),
shGetFileInfoLen,
shGetFileInfoFlags,
)
if ret != 0 && buf[2] > 0 {
return int(buf[2])
}
return 0
}
// From: "46EB5926-582E-4017-9FDF-E8998DAA0950"
var IID_IImageList = GUID{0x46eb5926, 0x582e, 0x4017, [8]byte{0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x09, 0x50}}
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373931.aspx
type GUID struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}
type IImageList struct {
Vtbl *IImageListVtbl
}
type IImageListVtbl struct {
Add uintptr
ReplaceIcon uintptr
SetOverlayImage uintptr
Replace uintptr
AddMasked uintptr
Draw uintptr
Remove uintptr
GetIcon uintptr
GetImageInfo uintptr
Copy uintptr
Merge uintptr
Clone uintptr
GetImageRect uintptr
GetIconSize uintptr
SetIconSize uintptr
GetImageCount uintptr
SetImageCount uintptr
SetBkColor uintptr
GetBkColor uintptr
BeginDrag uintptr
EndDrag uintptr
DragEnter uintptr
DragLeave uintptr
DragMove uintptr
SetDragCursorImage uintptr
DragShowNolock uintptr
GetDragImage uintptr
GetItemFlags uintptr
GetOverlayImage uintptr
}
Oh, I see the actual problem now.
uintptr(unsafe.Pointer(&IID_IImageList2)),
...
var IID_IImageList2 = &GUID{0x192b9d83, 0x50fc, 0x457b, [8]byte{0x90, 0xa0, 0x2b, 0x82, 0xa8, 0xb5, 0xda, 0xe1}}
Your IID_IImageList2 is already a pointer. In your call, you're taking a pointer to that pointer, which means the address is used as the GUID. You should either do
uintptr(unsafe.Pointer(&IID_IImageList2)),
...
var IID_IImageList2 = GUID{0x192b9d83, 0x50fc, 0x457b, [8]byte{0x90, 0xa0, 0x2b, 0x82, 0xa8, 0xb5, 0xda, 0xe1}}
or
uintptr(unsafe.Pointer(IID_IImageList2)),
...
var IID_IImageList2 = &GUID{0x192b9d83, 0x50fc, 0x457b, [8]byte{0x90, 0xa0, 0x2b, 0x82, 0xa8, 0xb5, 0xda, 0xe1}}
That way, the GUID itself is used as the GUID, not its location in memory.
Interfacing COM with Go is going to be painful.
A COM interface like IImageList2 is a list of function pointers, and you can't use those C function pointers from Go directly; you have to use syscall.Syscall() and its siblings (depending on the number of arguments the individual function takes) to call them.
At its core, a COM interface instance is a structure whose first and only field is a pointer to this list of methods. So it'd be something along the lines of
type IImageList2Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
|
type IImageList2 struct {
Vtbl *IImageList2Vtbl
}
When you pass a pointer to a variable of type IImageList2 to the Windows API function you call to create that object, be it SHGetImageList(), CoCreateInstance(), D3D11CreateDeviceAndSwapChain(), or what have you, the system will fill in the Vtbl entry with a pointer in read-only system memory that contains the list of functions.
So the first thing you have to do is make sure the methods are in the right order, so the Go structure IImageList2Vtbl and the list that Windows will give you match. Unfortunately, MSDN isn't good at this; you'll have to spelunk through the header files. Here's what I get:
type IImageList2Vtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
Add uintptr
ReplaceIcon uintptr
SetOverlayImage uintptr
Replace uintptr
AddMasked uintptr
Draw uintptr
Remove uintptr
GetIcon uintptr
GetImageInfo uintptr
Copy uintptr
Merge uintptr
Clone uintptr
GetImageRect uintptr
GetIconSize uintptr
SetIconSize uintptr
GetImageCount uintptr
SetImageCount uintptr
SetBkColor uintptr
GetBkColor uintptr
BeginDrag uintptr
EndDrag uintptr
DragEnter uintptr
DragLeave uintptr
DragMove uintptr
SetDragCursorImage uintptr
DragShowNolock uintptr
GetDragImage uintptr
GetItemFlags uintptr
GetOverlayImage uintptr
Resize uintptr
GetOriginalSize uintptr
SetOriginalSize uintptr
SetCallback uintptr
GetCallback uintptr
ForceImagePresent uintptr
DiscardImages uintptr
PreloadImages uintptr
GetStatistics uintptr
Initialize uintptr
Replace2 uintptr
ReplaceFromImageList uintptr
}
I'm sure I got this wrong; please report any errors. :)
This comes from commoncontrols.h. Go with the C-style, not C++-style, interface definitions (if there are more than one), as that will have all the methods, including those of interfaces that IImageList2 derives from (IUnknown, which all interfaces derive from, and IImageList).
Er wait, I lied: Windows doesn't expect you to give it the memory for the IImageList2. That's because COM interfaces are just like Go interfaces: they're a set of methods that any implementation can implement. So in reality you have to let Windows give you a pointer to an IImageList2, not an IImageList2Vtbl.
So what do we do? We store each instance as a pointer to the interface, and then pass a pointer to that to the creation functions.
So from that, we have
var imglist *IImageList2
hr, _, _ := procSHGetImageList.Call(
uintptr(SHIL_JUMBO),
uintptr(unsafe.Pointer(&IID_IImageList2)),
uintptr(unsafe.Pointer(&imglist)),
)
Notice that we pass a pointer to the IImageList2. I'll call this the instance, and the Vtbl member the vtable.
Now when you want to call a method, you have to add an extra first parameter: the instance itself. You can look on MSDN for the return types and other parameters:
// HRESULT EndDrag(void);
hr, _, _ = syscall.Syscall(instance.Vtbl.EndDrag,
uintptr(unsafe.Pointer(imglist)))
// HRESULT SetOverlayImage(int, int);
hr, _, _ = syscall.Syscall(instance.Vtbl.SetOverlayImage,
uintptr(unsafe.Pointer(imglist)),
4,
2)
Notice that we pass imglist this time, not &imglist.
Now because C and C++ don't support multiple returns like Go does, functions typically return a HRESULT (the COM equivalent of Go's error) and have you pass in pointers to the rest of the return values at the end of the argument list. For other COM interfaces, we follow the rules above. For other type, we refer to the Windows Data Types page to see what each named type represents, and remember that C int is always Go int32 on Windows, even on 64-bit systems.
// HRESULT AddMasked(HBITMAP, COLORREF, (OUT) int *);
// we'll use uintptr for HBITMAP and int32 for COLORREF
var index int32
hr, _, _ = syscall.Syscall(instance.Vtbl.AddMasked,
uintptr(unsafe.Pointer(instance)),
hbitmap,
mask,
uintptr(unsafe.Pointer(&index)))
Finally, COM requires us to call the Release() method when we're done with an object. This takes no extra parameters and its return value is irrelevant. You can stuff this in a defer if you want.
syscall.Syscall(instance.Vtbl.Release,
uintptr(unsafe.Pointer(instance)))
Note: I don't know if SHGetImageList() requires COM to be initialized. If it doesn't, ignore this part until you need some other COM interface.
Oh but that's not enough, because you also have to initialize COM. And COM can operate in a number of threading models. Only two are important: single-threaded apartment, which is used for anything related to GUI, and multithreaded apartment, which is used for special purposes.
The CoInitialize(), CoInitializeEx(), and CoUninitialize() functions all handle COM initialization and uninitialization. You already know how to call them; they're just normal DLL functions.
But beware! If you need a single-threaded apartment, you have to use runtime.LockOSThread() to ensure Go doesn't move the current goroutine to another OS thread from under you. If you don't do this, things will break in bizarre ways.
This is all a load of work, and you have to do it for every interface you're going to use. You might as well use a package that someone already made that does the heavy lifting for you. There are several packages, such as go-ole, that do the basic stuff. I don't see one that provides IImageList2, but you might be able to piggyback off an existing one. There seems to be only one reference for IImageList.
Good luck!
Tries to call GetVolumeInformation function from golang. Want to get volume name.
Use spec's of api:
BOOL WINAPI GetVolumeInformation(
_In_opt_ LPCTSTR lpRootPathName,
_Out_opt_ LPTSTR lpVolumeNameBuffer,
_In_ DWORD nVolumeNameSize,
_Out_opt_ LPDWORD lpVolumeSerialNumber,
_Out_opt_ LPDWORD lpMaximumComponentLength,
_Out_opt_ LPDWORD lpFileSystemFlags,
_Out_opt_ LPTSTR lpFileSystemNameBuffer,
_In_ DWORD nFileSystemNameSize
);
Use code:
// test
package main
import (
"fmt"
"syscall"
"unsafe"
)
func main() {
var lpRootPathName = "C:\\"
var lpVolumeNameBuffer string
var nVolumeNameSize uint64
var lpVolumeSerialNumber uint64
var lpMaximumComponentLength uint64
var lpFileSystemFlags uint64
var lpFileSystemNameBuffer string
var nFileSystemNameSize uint32
kernel32, _ := syscall.LoadLibrary("kernel32.dll")
getVolume, _ := syscall.GetProcAddress(kernel32, "GetVolumeInformationW")
var nargs uintptr = 8
ret, _, callErr := syscall.Syscall9(uintptr(getVolume),
nargs,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpRootPathName))),
uintptr(unsafe.Pointer(&lpVolumeNameBuffer)),
uintptr(unsafe.Pointer(&nVolumeNameSize)),
uintptr(unsafe.Pointer(&lpVolumeSerialNumber)),
uintptr(unsafe.Pointer(&lpMaximumComponentLength)),
uintptr(unsafe.Pointer(&lpFileSystemFlags)),
uintptr(unsafe.Pointer(&lpFileSystemNameBuffer)),
uintptr(unsafe.Pointer(&nFileSystemNameSize)),
0)
fmt.Println(ret, callErr, lpVolumeNameBuffer)
}
... and finally have error :(
unexpected fault address 0xffffffffffffffff
fatal error: fault
[signal 0xc0000005 code=0x0 addr=0xffffffffffffffff pc=0x456b11]
Don't understand and google cant'd help with calling winapi functions and returng string as result.
Thank's.
Package unsafe
Package unsafe contains operations that step around the type safety of
Go programs.
type Pointer
type Pointer *ArbitraryType
Pointer represents a pointer to an arbitrary type. There are four
special operations available for type Pointer that are not available
for other types.
1) A pointer value of any type can be converted to a Pointer.
2) A Pointer can be converted to a pointer value of any type.
3) A uintptr can be converted to a Pointer.
4) A Pointer can be converted to a uintptr.
Pointer therefore allows a program to defeat the type system and read
and write arbitrary memory. It should be used with extreme care.
You failed to heed the warning that unsafe.Pointer "should be used with extreme care."
Try this:
package main
import (
"fmt"
"syscall"
"unsafe"
)
func main() {
var RootPathName = `C:\`
var VolumeNameBuffer = make([]uint16, syscall.MAX_PATH+1)
var nVolumeNameSize = uint32(len(VolumeNameBuffer))
var VolumeSerialNumber uint32
var MaximumComponentLength uint32
var FileSystemFlags uint32
var FileSystemNameBuffer = make([]uint16, 255)
var nFileSystemNameSize uint32 = syscall.MAX_PATH + 1
kernel32, _ := syscall.LoadLibrary("kernel32.dll")
getVolume, _ := syscall.GetProcAddress(kernel32, "GetVolumeInformationW")
var nargs uintptr = 8
ret, _, callErr := syscall.Syscall9(uintptr(getVolume),
nargs,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(RootPathName))),
uintptr(unsafe.Pointer(&VolumeNameBuffer[0])),
uintptr(nVolumeNameSize),
uintptr(unsafe.Pointer(&VolumeSerialNumber)),
uintptr(unsafe.Pointer(&MaximumComponentLength)),
uintptr(unsafe.Pointer(&FileSystemFlags)),
uintptr(unsafe.Pointer(&FileSystemNameBuffer[0])),
uintptr(nFileSystemNameSize),
0)
fmt.Println(ret, callErr, syscall.UTF16ToString(VolumeNameBuffer))
}
I don't know the exact problem you are having but I think it is likely because you are not using the functions in https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go related to converting from the format that comes out of the kernel to what Go needs. Look at other callers to UTF16ToString, like in env_windows.go, to see how they are used.
Im currently trying to use user32.dll EnumWindows on Go but seems to not be working
var(
user32 = syscall.NewLazyDLL("user32.dll")
procEnumWindows = user32.NewProc("EnumWindows")
)
func EnumWindows() int {
ret, _, _ := procEnumWindows.Call(
syscall.NewCallback(enumWindowsProc),
uintptr(0),
)
return int(ret)
}
func enumWindowsProc(hwnd syscall.Handle, lparam uintptr) bool {
return true
}
Calling EnumWindows will give the following error:
panic: compileCallback: output parameter size is wrong
Im not sure how should I use the syscall package... I cant seem to find enough documentation on it
On the MSDN doc page it says that the callback should return a BOOL and thats what I am doing?
BOOL in WinAPI is declared as typedef int BOOL. So it doesn't match Go's bool. Specifications doesn't even mention what's the size it has. It's probably 1 byte but it doesn't say it. You should use int32 instead.
How do I obtain the underlying syscall.Handle for a *net.UDPConn on Windows? I want this handle to set the IP_MULTICAST_TTL via syscall.SetsockoptInt. On Linux I do the following:
func setTTL(conn *net.UDPConn, ttl int) error {
f, err := conn.File()
if err != nil {
return err
}
defer f.Close()
fd := int(f.Fd())
return syscall.SetsockoptInt(fd, syscall.SOL_IP, syscall.IP_MULTICAST_TTL, ttl)
}
But on Windows, the implicit dup inside *net.UDPConn's File() fails with:
04:24:49 main.go:150: dup: not supported by windows
And in the source code is marked as a to-do. How can I get this handle? Is there some other way to set the TTL if not?
Update0
I've submitted the shortcomings to the Go issue tracker:
SetTTL for *net.UDPConn
Implement dup for netFD on Windows
The short answer is impossible. But since that isn't an answer you want to hear, I will give you the right way and wrong way to solve the problem.
The right way:
implement dup() for Windows.
submit to Go as a changeset
wait for it to be released to use it
Obviously the right way has some issues... but I highly recommend doing it. Go needs windows developers to fix up these types of serious problems. The only reason this can't be done in Windows is no one implemented the function
The wrong way:
Until the patch you write gets accepted and released, you can fake it through unsafe. The way the following code works by mirroring the exact structure of a net.UDPConn. This included copying over all structs from net that make up a UDPConn. Then unsafe is used to assert that the local UDPConn is the same as net's UDPConn. The compiler can not check this and takes your word for it. Were the internals of net to ever change, it would compile but god knows what it would do.
All code is untested.
package reallyunsafenet
import (
"net"
"sync"
"syscall"
"unsafe"
)
// copied from go/src/pkg/net/fd_windows.go
type ioResult struct {
qty uint32
err error
}
// copied from go/src/pkg/net/fd_windows.go
type netFD struct {
// locking/lifetime of sysfd
sysmu sync.Mutex
sysref int
closing bool
// immutable until Close
sysfd syscall.Handle
family int
sotype int
isConnected bool
net string
laddr net.Addr
raddr net.Addr
resultc [2]chan ioResult
errnoc [2]chan error
// owned by client
rdeadline int64
rio sync.Mutex
wdeadline int64
wio sync.Mutex
}
// copied from go/src/pkg/net/udpsock_posix.go
type UDPConn struct {
fd *netFD
}
// function to get fd
func GetFD(conn *net.UDPConn) syscall.Handle {
c := (*UDPConn)(unsafe.Pointer(conn))
return c.fd.sysfd
}