首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何正确初始化COM对象?

如何正确初始化COM对象?
EN

Stack Overflow用户
提问于 2022-09-21 21:37:52
回答 1查看 83关注 0票数 1

我试图使用win32 api通过IDiskQuotaControl接口获取IDiskQuotaControl接口中的卷的配额状态

我遇到的问题似乎与初始化有关。请看下面的代码。

代码语言:javascript
运行
复制
//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),我都会得到成功的返回。

结果:

代码语言:javascript
运行
复制
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)中的错误翻译为“未初始化此对象”

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-22 08:04:47

IDiskQuotaControl接口文档:

IDiskQuotaControl接口继承自IUnknown接口。

这是错误的!IDiskQuotaControl来自IConnectionPointContainer,而不是IUnknown。你可以在dskquota.h中看到这一点

代码语言:javascript
运行
复制
DECLARE_INTERFACE_IID_(IDiskQuotaControl, IConnectionPointContainer, "7988B572-EC89-11cf-9C00-00AA00A14F56")

因此,您的vtable定义是错误的,您必须在ReleaseInitialize方法之间添加两个方法。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73807191

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档