我正在嘗試通過IDiskQuotaControl 介面使用 win32 api 在 Windows 中獲取卷的配額狀態
我遇到的問題似乎與初始化有關。請看下面的代碼。
//go:build windows && amd64
package main
import (
"flag"
"fmt"
"runtime"
"sync"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// START OF basic stuff
const COINIT_APARTMENTTHREADED = 0x2
const CLSCTX_INPROC_SERVER = 0x1
const CLSCTX_INPROC_HANDLER = 0x2
const CLSCTX_LOCAL_SERVER = 0x4
var (
modole32 = syscall.NewLazyDLL("ole32.dll")
procCoInitializeEx = modole32.NewProc("CoInitializeEx")
procCoUninitialize = modole32.NewProc("CoUninitialize")
procCoCreateInstance = modole32.NewProc("CoCreateInstance")
)
func CoInitializeEx(pvReserved uintptr, dwCoInit uint32) (r1, r2 uintptr, lastErr error) {
r1, r2, lastErr = procCoInitializeEx.Call(
uintptr(pvReserved),
uintptr(dwCoInit),
)
return
}
func CoUninitialize() (r1, r2 uintptr, lastErr error) {
r1, r2, lastErr = procCoUninitialize.Call()
return
}
func CoCreateInstance(rclsid *GUID, pUnkOuter *byte, dwClsContext uint32, riid *GUID, ppv *uintptr) (r1, r2 uintptr, lastErr error) {
r1, r2, lastErr = procCoCreateInstance.Call(
uintptr(unsafe.Pointer(rclsid)),
uintptr(unsafe.Pointer(pUnkOuter)),
uintptr(dwClsContext),
uintptr(unsafe.Pointer(riid)),
uintptr(unsafe.Pointer(ppv)),
)
return
}
type GUID struct {
Data1 uint32
Data2 uint16
Data3 uint16
Data4 [8]byte
}
type IDiskQuotaControl struct {
lpVtbl *IDiskQuotaControlVtbl
}
type IDiskQuotaControlVtbl struct {
QueryInterface uintptr
AddRef uintptr
Release uintptr
Initialize uintptr
SetQuotaState uintptr
GetQuotaState uintptr
SetQuotaLogFlags uintptr
GetQuotaLogFlags uintptr
SetDefaultQuotaThreshold uintptr
GetDefaultQuotaThreshold uintptr
GetDefaultQuotaThresholdText uintptr
SetDefaultQuotaLimit uintptr
GetDefaultQuotaLimit uintptr
GetDefaultQuotaLimitText uintptr
AddUserSid uintptr
AddUserName uintptr
DeleteUser uintptr
FindUserSid uintptr
FindUserName uintptr
CreateEnumUsers uintptr
CreateUserBatch uintptr
InvalidateSidNameCache uintptr
GiveUserNameResolutionPriority uintptr
ShutdownNameResolution uintptr
}
func (x *IDiskQuotaControl) AddRef() (r1, r2 uintptr, lastErr error) {
r1, r2, lastErr = syscall.SyscallN(
x.lpVtbl.AddRef,
uintptr(unsafe.Pointer(x)),
)
return
}
func (x *IDiskQuotaControl) Release() (r1, r2 uintptr, lastErr error) {
r1, r2, lastErr = syscall.SyscallN(
x.lpVtbl.Release,
uintptr(unsafe.Pointer(x)),
)
return
}
func (x *IDiskQuotaControl) Initialize(pszPath *uint16, bReadWrite int32) (r1, r2 uintptr, lastErr error) {
r1, r2, lastErr = syscall.SyscallN(
x.lpVtbl.Initialize,
uintptr(unsafe.Pointer(x)),
uintptr(unsafe.Pointer(pszPath)),
uintptr(bReadWrite),
)
return
}
func (x *IDiskQuotaControl) GetQuotaState(pdwState *uint32) (r1, r2 uintptr, lastErr error) {
r1, r2, lastErr = syscall.SyscallN(
x.lpVtbl.GetQuotaState,
uintptr(unsafe.Pointer(x)),
uintptr(unsafe.Pointer(pdwState)),
)
return
}
func (x *IDiskQuotaControl) GetDefaultQuotaLimit(pllLimit *int64) (r1, r2 uintptr, lastErr error) {
r1, r2, lastErr = syscall.SyscallN(
x.lpVtbl.GetDefaultQuotaLimit,
uintptr(unsafe.Pointer(x)),
uintptr(unsafe.Pointer(pllLimit)),
)
return
}
var CLSID_DiskQuotaControl = &GUID{0x7988b571, 0xec89, 0x11cf, [8]byte{0x9c, 0x0, 0x0, 0xaa, 0x0, 0xa1, 0x4f, 0x56}}
var IID_IDiskQuotaControl = &GUID{0x7988b572, 0xec89, 0x11cf, [8]byte{0x9c, 0x0, 0x0, 0xaa, 0x0, 0xa1, 0x4f, 0x56}}
// END OF basic stuff
func getVolumeQuota(wg *sync.WaitGroup, volume string) {
defer wg.Done()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
// Init COM
r1, r2, lastErr := CoInitializeEx(
0, // must be NULL
COINIT_APARTMENTTHREADED,
)
defer CoUninitialize()
fmt.Println("CoInitializeEx", r1, r2, lastErr) // Print results for debug
// Create a COM instance
var ppv uintptr
r1, r2, lastErr = CoCreateInstance(
CLSID_DiskQuotaControl,
nil,
CLSCTX_INPROC_SERVER,
IID_IDiskQuotaControl,
&ppv,
)
fmt.Println("CoCreateInstance", r1, r2, lastErr)
diskQuotaControl := (*IDiskQuotaControl)(unsafe.Pointer(ppv))
defer diskQuotaControl.Release()
pszPath, err := windows.UTF16PtrFromString(volume)
if err != nil {
panic(err)
}
// Initialize seems to fail even the return is a success
r1, r2, lastErr = diskQuotaControl.Initialize(
pszPath,
0, // false => read only
)
fmt.Println("Initialize", r1, r2, lastErr)
var pdwState uint32
r1, r2, lastErr = diskQuotaControl.GetQuotaState(
&pdwState,
)
fmt.Println("GetQuotaState", r1, r2, lastErr)
fmt.Println(pdwState)
var pllLimit int64
r1, r2, lastErr = diskQuotaControl.GetDefaultQuotaLimit(
&pllLimit,
)
fmt.Println("GetDefaultQuotaLimit", r1, r2, lastErr)
fmt.Println(pllLimit)
}
func main() {
volume := flag.String("v", `C:\`, "volume")
flag.Parse()
fmt.Println("Volume", *volume)
var wg sync.WaitGroup
wg.Add(1)
go getVolumeQuota(&wg, *volume)
wg.Wait()
}
我認為問題出在 Initialize 的原因是,無論我輸入什么輸入(使用標志 -v),我總是得到成功回傳。
結果:
Volume C:\
CoInitializeEx 0 0 The operation completed successfully.
CoCreateInstance 0 0 The operation completed successfully.
Initialize 0 9298000 The operation completed successfully.
GetQuotaState 2147942403 9298000 The system cannot find the path specified.
0
GetDefaultQuotaLimit 2147942421 9298000 The operation completed successfully.
0
Volume \\?\C:\
CoInitializeEx 0 0 The operation completed successfully.
CoCreateInstance 0 0 The operation completed successfully.
Initialize 0 9103168 The operation completed successfully.
GetQuotaState 2147942403 9103168 The system cannot find the path specified.
0
GetDefaultQuotaLimit 2147942421 9103168 The operation completed successfully.
0
Volume Invalid:Volume://
CoInitializeEx 0 0 The operation completed successfully.
CoCreateInstance 0 0 The operation completed successfully.
Initialize 0 8709600 The operation completed successfully.
GetQuotaState 2147942403 8709600 The system cannot find the path specified.
0
GetDefaultQuotaLimit 2147942421 8709600 The operation completed successfully.
0
GetDefaultQuotaLimit (2147942421 = 0x80070015) 中的錯誤轉換為“此物件尚未初始化”
uj5u.com熱心網友回復:
IDiskQuotaControl介面檔案:
IDiskQuotaControl 介面繼承自IUnknown介面。
是錯的!IDiskQuotaControl從IConnectionPointContainer派生,而不是從IUnknown. 您可以在dskquota.h中看到:
DECLARE_INTERFACE_IID_(IDiskQuotaControl, IConnectionPointContainer, "7988B572-EC89-11cf-9C00-00AA00A14F56")
所以,你的 vtable 定義是錯誤的,你必須在你的Release和方法之間添加兩個Initialize方法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/512758.html
標籤:去温纳皮com
