2013-12-04 7 views
12

से मैं जाओ से WMI प्रश्नों को चलाने के लिए चाहते हैं। जाओ से call DLL functions के तरीके हैं। मेरी समझ यह है कि वहां कुछ डीएलएल होना चाहिए, जहां सही कॉल के साथ, कुछ डेटा लौटाएगा जो मैं पार्स और उपयोग कर सकता हूं। मैं सी या सी ++ में कॉल करने से बचना पसंद करूंगा, खासकर जब से मुझे लगता है कि वे विंडोज एपीआई पर ही रैपर हैं।क्वेरी WMI जाओ

मैं dumpbin.exe /exports c:\windows\system32\wmi.dll के उत्पादन की जांच की है, और निम्न प्रविष्टि होनहार लग रहा है:

WmiQueryAllDataA (forwarded to wmiclnt.WmiQueryAllDataA)

हालांकि मैं यहाँ से क्या करना है यकीन नहीं है। इस समारोह में क्या तर्क हैं? यह वापस क्या करता है? WmiQueryAllDataA के लिए खोजना उपयोगी नहीं है। और वह नाम केवल c:\program files (x86)\windows kits\8.1\include\shared\wmistr.h की टिप्पणी में दिखाई देता है, लेकिन कोई फ़ंक्शन हस्ताक्षर नहीं है।

वहाँ बेहतर तरीकों हैं? क्या कोई और डीएलएल है? क्या मैं कुछ भूल रहा हूँ? क्या मुझे सिर्फ एक सी wrapper का उपयोग करना चाहिए?

.NET प्रतिबिंबक के साथ लिंकपैड में एक डब्ल्यूएमआई क्वेरी चलाना WmiNetUtilsHelper:ExecQueryWmi (और _f संस्करण) का उपयोग दिखाता है, लेकिन न तो एक देखने योग्य कार्यान्वयन है।

अद्यतन:github.com/StackExchange/wmi पैकेज का उपयोग करें जो स्वीकृत उत्तर में समाधान का उपयोग करता है।

+0

केविन का उत्तर अब गिथब पर एक गो पैकेज में लागू किया गया है। Http://godoc.org/github.com/StackExchange/wmi –

उत्तर

17

COM की अद्भुत दुनिया में आपका स्वागत है, से जब सी ++ "एक युवा नवोदय" था सी में ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग।

गीथब mattn पर little wrapper in Go को एक साथ फेंक दिया गया है, जिसे मैं एक त्वरित उदाहरण प्रोग्राम को फेंकने के लिए उपयोग करता था। "यह भंडार प्रयोग के लिए बनाया गया था और अस्थिर माना जाना चाहिए।" सभी तरह के आत्मविश्वास पैदा करता है।

मैं त्रुटि जाँच का एक बहुत बाहर जा रहा हूँ। जब मैं कहता हूं तो मेरा विश्वास करो, आप इसे वापस जोड़ना चाहेंगे।

package main 

import (
     "github.com/mattn/go-ole" 
     "github.com/mattn/go-ole/oleutil" 
) 

func main() { 
    // init COM, oh yeah 
    ole.CoInitialize(0) 
    defer ole.CoUninitialize() 

    unknown, _ := oleutil.CreateObject("WbemScripting.SWbemLocator") 
    defer unknown.Release() 

    wmi, _ := unknown.QueryInterface(ole.IID_IDispatch) 
    defer wmi.Release() 

    // service is a SWbemServices 
    serviceRaw, _ := oleutil.CallMethod(wmi, "ConnectServer") 
    service := serviceRaw.ToIDispatch() 
    defer service.Release() 

    // result is a SWBemObjectSet 
    resultRaw, _ := oleutil.CallMethod(service, "ExecQuery", "SELECT * FROM Win32_Process") 
    result := resultRaw.ToIDispatch() 
    defer result.Release() 

    countVar, _ := oleutil.GetProperty(result, "Count") 
    count := int(countVar.Val) 

    for i :=0; i < count; i++ { 
     // item is a SWbemObject, but really a Win32_Process 
     itemRaw, _ := oleutil.CallMethod(result, "ItemIndex", i) 
     item := itemRaw.ToIDispatch() 
     defer item.Release() 

     asString, _ := oleutil.GetProperty(item, "Name") 

     println(asString.ToString()) 
    } 
} 

असली मांस ExecQuery करने के लिए कॉल है, मैं available classes से Win32_Process हड़पने के लिए यह समझना और प्रिंट करने के लिए आसान है, क्योंकि हो।

मेरी मशीन पर, यह प्रिंट:

System Idle Process 
System 
smss.exe 
csrss.exe 
wininit.exe 
services.exe 
lsass.exe 
svchost.exe 
svchost.exe 
atiesrxx.exe 
svchost.exe 
svchost.exe 
svchost.exe 
svchost.exe 
svchost.exe 
spoolsv.exe 
svchost.exe 
AppleOSSMgr.exe 
AppleTimeSrv.exe 
... and so on 
go.exe 
main.exe 

मैं इसे ऊंचा या यूएसी विकलांग के साथ नहीं चल रहा हूँ, लेकिन कुछ WMI प्रदाताओं वाला हैं एक विशेषाधिकार प्राप्त उपयोगकर्ता की आवश्यकता है।

मैं भी 100% है कि यह एक छोटे से लीक नहीं होगा नहीं कर रहा हूँ, तो आप उस में खुदाई करने के लिए चाहता हूँ। COM ऑब्जेक्ट्स संदर्भ गिना जाता है, इसलिए defer वहां एक बहुत अच्छा फिट होना चाहिए (बशर्ते विधि लंबे समय तक पागल न हो) लेकिन गो-ओले में कुछ जादू हो सकता है, मैंने नोटिस नहीं किया था।

+0

देखें COM का उपयोग करने का एकमात्र तरीका है? हालांकि उपरोक्त काम करता है, क्या डीएलएल को सीधे कॉल करना संभव है? – mjibson

+0

@mjibson सब कुछ रैपिंग COM को कॉल करता है, यह WMI के लिए मूल इंटरफ़ेस है। (देखें: http://msdn.microsoft.com/en-us/library/aa384642(v=vs.85).aspx; विशेष रूप से "सभी डब्लूएमआई इंटरफेस घटक ऑब्जेक्ट मॉडल (COM) पर आधारित होते हैं") –

+0

@mjibson कहा जा रहा है, ऐसी कुछ भाषाएं हैं जिनमें COM का उपयोग करके अधिक आसानी से सुविधाएं हैं। सी # की तरह :)। मेरे ज्ञान का सबसे अच्छा, जब तक कि आप एक .NET भाषा, या सी ++ में काम नहीं करना चाहते हैं, तो आप कुछ COM नृत्य "सी-स्टाइल" कर रहे हैं। आपके द्वारा देखी गई विशेष विधि [अनियंत्रित] है [http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/8b5064e0-d1f9-4986-a2e6-74fa9dd3bbc0/undocumented-wmi-api-in-advapi32dll? फोरम = windowssdk) (और अंत में ए भी बहुत डरावना है)। –

5

मैं एक साल बाद खत्म हो गया टिप्पणी कर रहा हूँ, लेकिन there is a solution here on github (और भावी पीढ़ी के लिए नीचे दिए गए पोस्ट)।

// +build windows 

/* 
Package wmi provides a WQL interface for WMI on Windows. 

Example code to print names of running processes: 

    type Win32_Process struct { 
     Name string 
    } 

    func main() { 
     var dst []Win32_Process 
     q := wmi.CreateQuery(&dst, "") 
     err := wmi.Query(q, &dst) 
     if err != nil { 
      log.Fatal(err) 
     } 
     for i, v := range dst { 
      println(i, v.Name) 
     } 
    } 

*/ 
package wmi 

import (
    "bytes" 
    "errors" 
    "fmt" 
    "log" 
    "os" 
    "reflect" 
    "runtime" 
    "strconv" 
    "strings" 
    "sync" 
    "time" 

    "github.com/mattn/go-ole" 
    "github.com/mattn/go-ole/oleutil" 
) 

var l = log.New(os.Stdout, "", log.LstdFlags) 

var (
    ErrInvalidEntityType = errors.New("wmi: invalid entity type") 
    lock     sync.Mutex 
) 

// QueryNamespace invokes Query with the given namespace on the local machine. 
func QueryNamespace(query string, dst interface{}, namespace string) error { 
    return Query(query, dst, nil, namespace) 
} 

// Query runs the WQL query and appends the values to dst. 
// 
// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in 
// the query must have the same name in dst. Supported types are all signed and 
// unsigned integers, time.Time, string, bool, or a pointer to one of those. 
// Array types are not supported. 
// 
// By default, the local machine and default namespace are used. These can be 
// changed using connectServerArgs. See 
// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details. 
func Query(query string, dst interface{}, connectServerArgs ...interface{}) error { 
    dv := reflect.ValueOf(dst) 
    if dv.Kind() != reflect.Ptr || dv.IsNil() { 
     return ErrInvalidEntityType 
    } 
    dv = dv.Elem() 
    mat, elemType := checkMultiArg(dv) 
    if mat == multiArgTypeInvalid { 
     return ErrInvalidEntityType 
    } 

    lock.Lock() 
    defer lock.Unlock() 
    runtime.LockOSThread() 
    defer runtime.UnlockOSThread() 

    err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED) 
    if err != nil { 
     oleerr := err.(*ole.OleError) 
     // S_FALSE   = 0x00000001 // CoInitializeEx was already called on this thread 
     if oleerr.Code() != ole.S_OK && oleerr.Code() != 0x00000001 { 
      return err 
     } 
    } else { 
     // Only invoke CoUninitialize if the thread was not initizlied before. 
     // This will allow other go packages based on go-ole play along 
     // with this library. 
     defer ole.CoUninitialize() 
    } 

    unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator") 
    if err != nil { 
     return err 
    } 
    defer unknown.Release() 

    wmi, err := unknown.QueryInterface(ole.IID_IDispatch) 
    if err != nil { 
     return err 
    } 
    defer wmi.Release() 

    // service is a SWbemServices 
    serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", connectServerArgs...) 
    if err != nil { 
     return err 
    } 
    service := serviceRaw.ToIDispatch() 
    defer serviceRaw.Clear() 

    // result is a SWBemObjectSet 
    resultRaw, err := oleutil.CallMethod(service, "ExecQuery", query) 
    if err != nil { 
     return err 
    } 
    result := resultRaw.ToIDispatch() 
    defer resultRaw.Clear() 

    count, err := oleInt64(result, "Count") 
    if err != nil { 
     return err 
    } 

    // Initialize a slice with Count capacity 
    dv.Set(reflect.MakeSlice(dv.Type(), 0, int(count))) 

    var errFieldMismatch error 
    for i := int64(0); i < count; i++ { 
     err := func() error { 
      // item is a SWbemObject, but really a Win32_Process 
      itemRaw, err := oleutil.CallMethod(result, "ItemIndex", i) 
      if err != nil { 
       return err 
      } 
      item := itemRaw.ToIDispatch() 
      defer itemRaw.Clear() 

      ev := reflect.New(elemType) 
      if err = loadEntity(ev.Interface(), item); err != nil { 
       if _, ok := err.(*ErrFieldMismatch); ok { 
        // We continue loading entities even in the face of field mismatch errors. 
        // If we encounter any other error, that other error is returned. Otherwise, 
        // an ErrFieldMismatch is returned. 
        errFieldMismatch = err 
       } else { 
        return err 
       } 
      } 
      if mat != multiArgTypeStructPtr { 
       ev = ev.Elem() 
      } 
      dv.Set(reflect.Append(dv, ev)) 
      return nil 
     }() 
     if err != nil { 
      return err 
     } 
    } 
    return errFieldMismatch 
} 

// ErrFieldMismatch is returned when a field is to be loaded into a different 
// type than the one it was stored from, or when a field is missing or 
// unexported in the destination struct. 
// StructType is the type of the struct pointed to by the destination argument. 
type ErrFieldMismatch struct { 
    StructType reflect.Type 
    FieldName string 
    Reason  string 
} 

func (e *ErrFieldMismatch) Error() string { 
    return fmt.Sprintf("wmi: cannot load field %q into a %q: %s", 
     e.FieldName, e.StructType, e.Reason) 
} 

var timeType = reflect.TypeOf(time.Time{}) 

// loadEntity loads a SWbemObject into a struct pointer. 
func loadEntity(dst interface{}, src *ole.IDispatch) (errFieldMismatch error) { 
    v := reflect.ValueOf(dst).Elem() 
    for i := 0; i < v.NumField(); i++ { 
     f := v.Field(i) 
     isPtr := f.Kind() == reflect.Ptr 
     if isPtr { 
      ptr := reflect.New(f.Type().Elem()) 
      f.Set(ptr) 
      f = f.Elem() 
     } 
     n := v.Type().Field(i).Name 
     if !f.CanSet() { 
      return &ErrFieldMismatch{ 
       StructType: f.Type(), 
       FieldName: n, 
       Reason:  "CanSet() is false", 
      } 
     } 
     prop, err := oleutil.GetProperty(src, n) 
     if err != nil { 
      errFieldMismatch = &ErrFieldMismatch{ 
       StructType: f.Type(), 
       FieldName: n, 
       Reason:  "no such struct field", 
      } 
      continue 
     } 
     defer prop.Clear() 

     switch val := prop.Value().(type) { 
     case int, int64: 
      var v int64 
      switch val := val.(type) { 
      case int: 
       v = int64(val) 
      case int64: 
       v = val 
      default: 
       panic("unexpected type") 
      } 
      switch f.Kind() { 
      case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 
       f.SetInt(v) 
      case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 
       f.SetUint(uint64(v)) 
      default: 
       return &ErrFieldMismatch{ 
        StructType: f.Type(), 
        FieldName: n, 
        Reason:  "not an integer class", 
       } 
      } 
     case string: 
      iv, err := strconv.ParseInt(val, 10, 64) 
      switch f.Kind() { 
      case reflect.String: 
       f.SetString(val) 
      case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 
       if err != nil { 
        return err 
       } 
       f.SetInt(iv) 
      case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 
       if err != nil { 
        return err 
       } 
       f.SetUint(uint64(iv)) 
      case reflect.Struct: 
       switch f.Type() { 
       case timeType: 
        if len(val) == 25 { 
         mins, err := strconv.Atoi(val[22:]) 
         if err != nil { 
          return err 
         } 
         val = val[:22] + fmt.Sprintf("%02d%02d", mins/60, mins%60) 
        } 
        t, err := time.Parse("20060102150405.000000-0700", val) 
        if err != nil { 
         return err 
        } 
        f.Set(reflect.ValueOf(t)) 
       } 
      } 
     case bool: 
      switch f.Kind() { 
      case reflect.Bool: 
       f.SetBool(val) 
      default: 
       return &ErrFieldMismatch{ 
        StructType: f.Type(), 
        FieldName: n, 
        Reason:  "not a bool", 
       } 
      } 
     default: 
      typeof := reflect.TypeOf(val) 
      if isPtr && typeof == nil { 
       break 
      } 
      return &ErrFieldMismatch{ 
       StructType: f.Type(), 
       FieldName: n, 
       Reason:  fmt.Sprintf("unsupported type (%T)", val), 
      } 
     } 
    } 
    return errFieldMismatch 
} 

type multiArgType int 

const (
    multiArgTypeInvalid multiArgType = iota 
    multiArgTypeStruct 
    multiArgTypeStructPtr 
) 

// checkMultiArg checks that v has type []S, []*S for some struct type S. 
// 
// It returns what category the slice's elements are, and the reflect.Type 
// that represents S. 
func checkMultiArg(v reflect.Value) (m multiArgType, elemType reflect.Type) { 
    if v.Kind() != reflect.Slice { 
     return multiArgTypeInvalid, nil 
    } 
    elemType = v.Type().Elem() 
    switch elemType.Kind() { 
    case reflect.Struct: 
     return multiArgTypeStruct, elemType 
    case reflect.Ptr: 
     elemType = elemType.Elem() 
     if elemType.Kind() == reflect.Struct { 
      return multiArgTypeStructPtr, elemType 
     } 
    } 
    return multiArgTypeInvalid, nil 
} 

func oleInt64(item *ole.IDispatch, prop string) (int64, error) { 
    v, err := oleutil.GetProperty(item, prop) 
    if err != nil { 
     return 0, err 
    } 
    defer v.Clear() 

    i := int64(v.Val) 
    return i, nil 
} 

// CreateQuery returns a WQL query string that queries all columns of src. where 
// is an optional string that is appended to the query, to be used with WHERE 
// clauses. In such a case, the "WHERE" string should appear at the beginning. 
func CreateQuery(src interface{}, where string) string { 
    var b bytes.Buffer 
    b.WriteString("SELECT ") 
    s := reflect.Indirect(reflect.ValueOf(src)) 
    t := s.Type() 
    if s.Kind() == reflect.Slice { 
     t = t.Elem() 
    } 
    if t.Kind() != reflect.Struct { 
     return "" 
    } 
    var fields []string 
    for i := 0; i < t.NumField(); i++ { 
     fields = append(fields, t.Field(i).Name) 
    } 
    b.WriteString(strings.Join(fields, ", ")) 
    b.WriteString(" FROM ") 
    b.WriteString(t.Name()) 
    b.WriteString(" " + where) 
    return b.String() 
} 
संबंधित मुद्दे