0

Windows サービスから Windows API と対話するアプリを作成しています。

@chowey hereからの多くの支援の後、私はちょっとコツをつかみ、GitHub hereに置いた基本的なライブラリを開始しました。

「サービス」に移りました。マシン上のすべての Windows サービスを一覧表示し、開始、停止、再起動する必要があります。操作するサービス ハンドルを取得すると、開始/停止/再起動は非常に簡単に見えますが、インストールされているサービスのリストを取得するのに苦労しています。

Advapi32.dllの EnumServicesStatusEx は、呼び出す必要がある関数ですが、ENUM_SERVICE_STATUS_PROCESS構造体の配列用に事前に割り当てられたメモリへのポインターが必要です。

null ポインターを使用して関数を呼び出すと、必要なメモリ割り当てサイズが返されますが、Go でメモリを直接割り当てる方法はないと思います。

最初は、メモリ割り当て要件を取得し、 unsafe パッケージを使用して構造体の SizeOf で割り、その要素数を含むスライスを作成し、最初の要素へのポインタを関数に渡すことができると思っていましたが、メモリは文字列データ用のスペースを含める必要がありますが、これはそうではありません。

これをどのように達成できるか知っている人はいますか?:)。

4

1 に答える 1

1

@alex からの提案の後、次のサンプル コードが動作するようになりました。

適切なサイズのバイト スライスを作成し、安全でないクラスを使用して構造体型にキャストしているようです。

    _, _, _ = svcEnumServicesStatusEx.Call(
        uintptr(handle),
        uintptr(uint32(SVC_SC_ENUM_PROCESS_INFO)),
        uintptr(uint32(SVC_SERVICE_WIN32)),
        uintptr(uint32(SVC_SERVICE_STATE_ALL)),
        uintptr(0),
        0,
        uintptr(unsafe.Pointer(&bytesReq)),
        uintptr(unsafe.Pointer(&numReturned)),
        uintptr(unsafe.Pointer(&resumeHandle)),
        uintptr(0),
    )

    if bytesReq > 0 {
        var buf []byte = make([]byte, bytesReq)

        ret, _, _ := svcEnumServicesStatusEx.Call(
            uintptr(handle),
            uintptr(uint32(SVC_SC_ENUM_PROCESS_INFO)),
            uintptr(uint32(SVC_SERVICE_WIN32)),
            uintptr(uint32(SVC_SERVICE_STATE_ALL)),
            uintptr(unsafe.Pointer(&buf[0])),
            uintptr(bytesReq),
            uintptr(unsafe.Pointer(&bytesReq)),
            uintptr(unsafe.Pointer(&numReturned)),
            uintptr(unsafe.Pointer(&resumeHandle)),
            uintptr(0),
        )

        if ret > 0 {
            var sizeTest ENUM_SERVICE_STATUS_PROCESS
            iter := uintptr(unsafe.Pointer(&buf[0]))

            for i := uint32(0); i < numReturned; i++ {
                var data *ENUM_SERVICE_STATUS_PROCESS = (*ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(iter))

                fmt.Printf("Service Name: %s - Display Name: %s - %#v\r\n", syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(data.lpServiceName))[:]), syscall.UTF16ToString((*[4096]uint16)(unsafe.Pointer(data.lpDisplayName))[:]), data.ServiceStatusProcess)

                iter = uintptr(unsafe.Pointer(iter + unsafe.Sizeof(sizeTest)))
            }
        } else {
            return nil, fmt.Errorf("Failed to get Service List even with allocated memory.")
        }
    } else {
        return nil, fmt.Errorf("Unable to get size of required memory allocation.")
    }
于 2016-05-20T15:40:16.293 に答える