func (wintun *Wintun) DataFileName() string {
	return fmt.Sprintf("\\\\.\\Global\\WINTUN_DEVICE_%s", guid.ToString((*windows.GUID)(wintun)))
}
DataFileName returns Wintun device data pipe name.
package wintun
import (
	"errors"
	"fmt"
	"strings"
	"syscall"
	"time"
	"unsafe"
	"golang.org/x/sys/windows"
	"golang.org/x/sys/windows/registry"
	"golang.zx2c4.com/wireguard/tun/wintun/guid"
	"golang.zx2c4.com/wireguard/tun/wintun/setupapi"
)
type Wintun windows.GUID
var deviceClassNetGUID = windows.GUID{Data1: 0x4d36e972, Data2: 0xe325, Data3: 0x11ce, Data4: [8]byte{0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}
const hardwareID = "Wintun"
const enumerator = ""
const machineName = ""
func GetInterface(ifname string, hwndParent uintptr) (*Wintun, error) {
	devInfoList, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, enumerator, hwndParent, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), machineName)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("SetupDiGetClassDevsEx(%v) failed: ", guid.ToString(&deviceClassNetGUID)) + err.Error())
	}
	defer devInfoList.Close()
	ifname = strings.ToLower(ifname)
	for index := 0; ; index++ {
		deviceData, err := devInfoList.EnumDeviceInfo(index)
		if err != nil {
			if errWin, ok := err.(syscall.Errno); ok && errWin == 259   {
				break
			}
			continue
		}
		ifid, err := devInfoList.GetInterfaceID(deviceData)
		if err != nil {
			continue
		}
		ifname2, err := ((*Wintun)(ifid)).GetInterfaceName()
		if err != nil {
			continue
		}
		if ifname == strings.ToLower(ifname2) {
			const driverType = setupapi.SPDIT_COMPATDRIVER
			err = devInfoList.BuildDriverInfoList(deviceData, driverType)
			if err != nil {
				return nil, errors.New("SetupDiBuildDriverInfoList failed: " + err.Error())
			}
			defer devInfoList.DestroyDriverInfoList(deviceData, driverType)
			for index := 0; ; index++ {
				driverData, err := devInfoList.EnumDriverInfo(deviceData, driverType, index)
				if err != nil {
					if errWin, ok := err.(syscall.Errno); ok && errWin == 259   {
						break
					}
					continue
				}
				driverDetailData, err := devInfoList.GetDriverInfoDetail(deviceData, driverData)
				if err != nil {
					continue
				}
				if driverDetailData.IsCompatible(hardwareID) {
					return (*Wintun)(ifid), nil
				}
			}
			return (*Wintun)(ifid), errors.New("Foreign network interface with the same name exists")
		}
	}
	return nil, nil
}
func CreateInterface(description string, hwndParent uintptr) (*Wintun, bool, error) {
	devInfoList, err := setupapi.SetupDiCreateDeviceInfoListEx(&deviceClassNetGUID, hwndParent, machineName)
	if err != nil {
		return nil, false, errors.New(fmt.Sprintf("SetupDiCreateDeviceInfoListEx(%v) failed: ", guid.ToString(&deviceClassNetGUID)) + err.Error())
	}
	className, err := setupapi.SetupDiClassNameFromGuidEx(&deviceClassNetGUID, machineName)
	if err != nil {
		return nil, false, errors.New(fmt.Sprintf("SetupDiClassNameFromGuidEx(%v) failed: ", guid.ToString(&deviceClassNetGUID)) + err.Error())
	}
	deviceData, err := devInfoList.CreateDeviceInfo(className, &deviceClassNetGUID, description, hwndParent, setupapi.DICD_GENERATE_ID)
	if err != nil {
		return nil, false, errors.New("SetupDiCreateDeviceInfo failed: " + err.Error())
	}
	err = devInfoList.SetSelectedDevice(deviceData)
	if err != nil {
		return nil, false, errors.New("SetupDiSetSelectedDevice failed: " + err.Error())
	}
	hwid, err := syscall.UTF16FromString(hardwareID)
	if err != nil {
		return nil, false, err  
	}
	err = devInfoList.SetDeviceRegistryProperty(deviceData, setupapi.SPDRP_HARDWAREID, setupapi.UTF16ToBuf(append(hwid, 0)))
	if err != nil {
		return nil, false, errors.New("SetupDiSetDeviceRegistryProperty(SPDRP_HARDWAREID) failed: " + err.Error())
	}
	const driverType = setupapi.SPDIT_CLASSDRIVER
	err = devInfoList.BuildDriverInfoList(deviceData, driverType)
	if err != nil {
		return nil, false, errors.New("SetupDiBuildDriverInfoList failed: " + err.Error())
	}
	defer devInfoList.DestroyDriverInfoList(deviceData, driverType)
	driverDate := windows.Filetime{}
	driverVersion := uint64(0)
	for index := 0; ; index++ {
		driverData, err := devInfoList.EnumDriverInfo(deviceData, driverType, index)
		if err != nil {
			if errWin, ok := err.(syscall.Errno); ok && errWin == 259   {
				break
			}
			continue
		}
		if driverData.IsNewer(driverDate, driverVersion) {
			driverDetailData, err := devInfoList.GetDriverInfoDetail(deviceData, driverData)
			if err != nil {
				continue
			}
			if driverDetailData.IsCompatible(hardwareID) {
				err := devInfoList.SetSelectedDriver(deviceData, driverData)
				if err != nil {
					continue
				}
				driverDate = driverData.DriverDate
				driverVersion = driverData.DriverVersion
			}
		}
	}
	if driverVersion == 0 {
		return nil, false, fmt.Errorf("No driver for device %q installed", hardwareID)
	}
	err = devInfoList.CallClassInstaller(setupapi.DIF_REGISTERDEVICE, deviceData)
	if err != nil {
		return nil, false, errors.New("SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed: " + err.Error())
	}
	devInfoList.CallClassInstaller(setupapi.DIF_REGISTER_COINSTALLERS, deviceData)
	devInfoList.CallClassInstaller(setupapi.DIF_INSTALLINTERFACES, deviceData)
	var wintun *Wintun
	var rebootRequired bool
	err = devInfoList.CallClassInstaller(setupapi.DIF_INSTALLDEVICE, deviceData)
	if err != nil {
		err = errors.New("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed: " + err.Error())
	}
	if err == nil {
		if ret, _ := checkReboot(devInfoList, deviceData); ret {
			rebootRequired = true
		}
		getInterface := func() (*Wintun, error) {
			keyDev, err := devInfoList.OpenDevRegKey(deviceData, setupapi.DICS_FLAG_GLOBAL, 0, setupapi.DIREG_DRV, registry.READ)
			if err != nil {
				return nil, errors.New("Device-specific registry key open failed: " + err.Error())
			}
			defer keyDev.Close()
			value, err := getRegStringValue(keyDev, "NetCfgInstanceId")
			if err != nil {
				if errWin, ok := err.(syscall.Errno); ok && errWin == windows.ERROR_FILE_NOT_FOUND {
					return nil, err
				}
				return nil, errors.New("RegQueryStringValue(\"NetCfgInstanceId\") failed: " + err.Error())
			}
			ifid, err := guid.FromString(value)
			if err != nil {
				return nil, fmt.Errorf("NetCfgInstanceId registry value is not a GUID (expected: \"{...}\", provided: %q)", value)
			}
			wintun := (*Wintun)(ifid)
			keyNetName := wintun.GetNetRegKeyName()
			keyNet, err := registry.OpenKey(registry.LOCAL_MACHINE, keyNetName, registry.QUERY_VALUE)
			if err != nil {
				if errWin, ok := err.(syscall.Errno); ok && errWin == windows.ERROR_FILE_NOT_FOUND {
					return nil, err
				}
				return nil, errors.New(fmt.Sprintf("RegOpenKeyEx(%q) failed: ", keyNetName) + err.Error())
			}
			defer keyNet.Close()
			_, valueType, err := keyNet.GetValue("Name", nil)
			if err != nil {
				if errWin, ok := err.(syscall.Errno); ok && errWin == windows.ERROR_FILE_NOT_FOUND {
					return nil, err
				}
				return nil, errors.New("RegQueryValueEx(\"Name\") failed: " + err.Error())
			}
			switch valueType {
			case registry.SZ, registry.EXPAND_SZ:
			default:
				return nil, fmt.Errorf("Interface name registry value is not REG_SZ or REG_EXPAND_SZ (expected: %v or %v, provided: %v)", registry.SZ, registry.EXPAND_SZ, valueType)
			}
			return wintun, nil
		}
		for numAttempts := 0; numAttempts < 30; numAttempts++ {
			wintun, err = getInterface()
			if err != nil {
				if errWin, ok := err.(syscall.Errno); ok && errWin == windows.ERROR_FILE_NOT_FOUND {
					err = errors.New("Time-out waiting for adapter to get ready")
					time.Sleep(time.Second / 4)
					continue
				}
			}
			break
		}
	}
	if err == nil {
		return wintun, rebootRequired, nil
	}
	removeDeviceParams := setupapi.RemoveDeviceParams{
		ClassInstallHeader: *setupapi.MakeClassInstallHeader(setupapi.DIF_REMOVE),
		Scope:              setupapi.DI_REMOVEDEVICE_GLOBAL,
	}
	if devInfoList.SetClassInstallParams(deviceData, &removeDeviceParams.ClassInstallHeader, uint32(unsafe.Sizeof(removeDeviceParams))) == nil {
		if devInfoList.CallClassInstaller(setupapi.DIF_REMOVE, deviceData) == nil {
			if ret, _ := checkReboot(devInfoList, deviceData); ret {
				rebootRequired = true
			}
		}
	}
	return nil, rebootRequired, err
}
func (wintun *Wintun) DeleteInterface(hwndParent uintptr) (bool, bool, error) {
	ifid := (*windows.GUID)(wintun)
	devInfoList, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, enumerator, hwndParent, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), machineName)
	if err != nil {
		return false, false, errors.New(fmt.Sprintf("SetupDiGetClassDevsEx(%v) failed: ", guid.ToString(&deviceClassNetGUID)) + err.Error())
	}
	defer devInfoList.Close()
	for index := 0; ; index++ {
		deviceData, err := devInfoList.EnumDeviceInfo(index)
		if err != nil {
			if errWin, ok := err.(syscall.Errno); ok && errWin == 259   {
				break
			}
			continue
		}
		ifid2, err := devInfoList.GetInterfaceID(deviceData)
		if err != nil {
			continue
		}
		if *ifid == *ifid2 {
			removeDeviceParams := setupapi.RemoveDeviceParams{
				ClassInstallHeader: *setupapi.MakeClassInstallHeader(setupapi.DIF_REMOVE),
				Scope:              setupapi.DI_REMOVEDEVICE_GLOBAL,
			}
			err = devInfoList.SetClassInstallParams(deviceData, &removeDeviceParams.ClassInstallHeader, uint32(unsafe.Sizeof(removeDeviceParams)))
			if err != nil {
				return false, false, errors.New("SetupDiSetClassInstallParams failed: " + err.Error())
			}
			err = devInfoList.CallClassInstaller(setupapi.DIF_REMOVE, deviceData)
			if err != nil {
				return false, false, errors.New("SetupDiCallClassInstaller failed: " + err.Error())
			}
			if ret, _ := checkReboot(devInfoList, deviceData); ret {
				return true, true, nil
			}
			return true, false, nil
		}
	}
	return false, false, nil
}
func (wintun *Wintun) FlushInterface() error {
	return nil
}
func checkReboot(deviceInfoSet setupapi.DevInfo, deviceInfoData *setupapi.DevInfoData) (bool, error) {
	devInstallParams, err := deviceInfoSet.GetDeviceInstallParams(deviceInfoData)
	if err != nil {
		return false, err
	}
	if (devInstallParams.Flags & (setupapi.DI_NEEDREBOOT | setupapi.DI_NEEDRESTART)) != 0 {
		return true, nil
	}
	return false, nil
}
func (wintun *Wintun) GetInterfaceName() (string, error) {
	key, err := registry.OpenKey(registry.LOCAL_MACHINE, wintun.GetNetRegKeyName(), registry.QUERY_VALUE)
	if err != nil {
		return "", errors.New("Network-specific registry key open failed: " + err.Error())
	}
	defer key.Close()
	return getRegStringValue(key, "Name")
}
func (wintun *Wintun) SetInterfaceName(ifname string) error {
	key, err := registry.OpenKey(registry.LOCAL_MACHINE, wintun.GetNetRegKeyName(), registry.SET_VALUE)
	if err != nil {
		return errors.New("Network-specific registry key open failed: " + err.Error())
	}
	defer key.Close()
	return key.SetStringValue("Name", ifname)
}
func (wintun *Wintun) GetNetRegKeyName() string {
	ifid := (*windows.GUID)(wintun)
	return fmt.Sprintf("SYSTEM\\CurrentControlSet\\Control\\Network\\%v\\%v\\Connection", guid.ToString(&deviceClassNetGUID), guid.ToString(ifid))
}
func getRegStringValue(key registry.Key, name string) (string, error) {
	value, valueType, err := key.GetStringValue(name)
	if err != nil {
		return "", err
	}
	if valueType != registry.EXPAND_SZ {
		return value, nil
	}
	valueExp, err := registry.ExpandString(value)
	if err != nil {
		return value, nil
	}
	return valueExp, nil
}