Skip to content

Instantly share code, notes, and snippets.

@WebFreak001
Last active May 29, 2020 09:37
Show Gist options
  • Save WebFreak001/7d2a31c2b8e7425c7db9c971d1a18ddc to your computer and use it in GitHub Desktop.
Save WebFreak001/7d2a31c2b8e7425c7db9c971d1a18ddc to your computer and use it in GitHub Desktop.
querying WMI in dlang over COM
// https://forum.dlang.org/post/dmmfzotxhlghialrsvyw@forum.dlang.org
//
// warning: this is not what you would consider good code, you want
// to make a proper library for the COM classes and types and make sure
// really all resources are freed. I mostly try to do so with all the
// scope(exit) expressions here but for example the VARIANT usage is
// actually wrong and should use proper types.
import core.stdc.config;
import core.stdc.stdio;
import core.sys.windows.com;
import core.sys.windows.oaidl;
import core.sys.windows.objidl;
import core.sys.windows.windows;
import core.sys.windows.wtypes;
void main(string[] args)
{
// port of https://docs.microsoft.com/en-us/windows/win32/wmisdk/example-creating-a-wmi-application
CoInitializeEx(null, COINIT.COINIT_MULTITHREADED)
.validateHResult("CoInitializeEx");
scope (exit)
CoUninitialize();
CoInitializeSecurity(null, // security descriptor
-1, // COM negotiates service
null, // Authentication services
null, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Impersonation
null, // Authentication info
EOLE_AUTHENTICATION_CAPABILITIES.EOAC_NONE, // Additional capabilities
null // Reserved
).validateHResult("CoInitializeSecurity");
IWbemLocator loc;
CoCreateInstance(&CLSID_WbemLocator, null, CLSCTX_INPROC_SERVER,
&IID_IWbemLocator, cast(void**)&loc).validateHResult(
"CoCreateInstance WbemLocator");
scope (exit)
loc.Release();
IWbemServices svc;
loc.ConnectServer("ROOT\\CIMV2", // WMI namespace
null, // username
null, // password
null, // locale
0, // security flags
null, // authority
null, // context object
&svc // IWbemServices proxy
).validateHResult("ConnectServer");
scope (exit)
svc.Release();
// Set the IWbemServices proxy so that impersonation
// of the user (client) occurs.
// WARNING V wrong D definition (wants IUnknown* instead of IUnknown which is already a reference type, cast overrides this)
CoSetProxyBlanket(cast(IUnknown*) svc, // the proxy to set
RPC_C_AUTHN_WINNT, // authentication service
RPC_C_AUTHZ_NONE, // authorization service
NULL, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // authentication level
RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
NULL, // client identity
EOLE_AUTHENTICATION_CAPABILITIES.EOAC_NONE // proxy capabilities
).validateHResult("CoSetProxyBlanket");
IEnumWbemClassObject enumerator;
svc.ExecQuery("WQL", "SELECT * FROM Win32_PnPEntity",
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
null, &enumerator).validateHResult("ExecQuery");
scope (exit)
enumerator.Release();
IWbemClassObject clsobj;
ULONG ureturn;
while (true)
{
enumerator.Next(WBEM_INFINITE,
1, &clsobj, &ureturn);
if (!ureturn)
break;
scope (exit)
clsobj.Release();
BSTR name;
VARIANT vtProp;
printf("\nEntry:\n");
clsobj.BeginEnumeration(0);
while (true)
{
enum WBEM_S_NO_MORE_DATA = 0x40005;
if (clsobj.Next(0, &name, &vtProp, null,
null) == WBEM_S_NO_MORE_DATA)
break;
printf("\t%ls: ", name);
SysFreeString(name);
// TODO: variant code suck
// check https://docs.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-variant
// and https://docs.microsoft.com/en-us/windows/win32/api/propidlbase/ns-propidlbase-propvariant
// to make this better
switch (vtProp.vt)
{
case VARENUM.VT_EMPTY:
printf("<empty>\n");
break;
case VARENUM.VT_NULL:
printf("null\n");
break;
case VARENUM.VT_VOID:
printf("void\n");
break;
case VARENUM.VT_I1:
printf("byte: %d\n",
cast(int) vtProp.bVal);
break;
case VARENUM.VT_UI1:
printf("ubyte: %d\n",
cast(int) vtProp.bVal);
break;
case VARENUM.VT_UI2:
printf("ushort: %d\n",
cast(int) vtProp.iVal);
break;
case VARENUM.VT_UI4:
case VARENUM.VT_UINT:
printf("uint: %u\n",
cast(uint) vtProp.intVal);
break;
case VARENUM.VT_I8:
printf("long: %ld\n",
cast(long) vtProp.llVal);
break;
case VARENUM.VT_UI8:
printf("ulong: %lu\n",
cast(ulong) vtProp.llVal);
break;
case VARENUM.VT_I2:
printf("short: %d\n",
cast(int) vtProp.iVal);
break;
case VARENUM.VT_I4:
case VARENUM.VT_INT:
printf("int: %d\n", vtProp.intVal);
break;
case VARENUM.VT_R4:
printf("float: %f\n", vtProp.fltVal);
break;
case VARENUM.VT_R8:
printf("double: %f\n", vtProp.dblVal);
break;
case VARENUM.VT_CY:
printf("currency: %ld\n",
vtProp.cyVal.int64);
break;
case VARENUM.VT_DATE:
printf("date: %lf\n", vtProp.date);
break;
case VARENUM.VT_BSTR:
printf("bstr: %ls\n", vtProp.bstrVal);
break;
case VARENUM.VT_BOOL:
if (vtProp.boolVal)
printf("true\n");
else
printf("false\n");
break;
default:
printf("<type %d>\n", vtProp.vt);
break;
}
VariantClear(&vtProp);
}
}
}
// type definitions, might as well move them to a library...
HRESULT validateHResult(HRESULT result, string what)
{
if (!FAILED(result))
return result;
else
throw new HResultException(result, what);
}
class HResultException : Exception
{
this(HRESULT hresult, string what,
string file = __FILE__, size_t line = __LINE__)
{
import std.conv : to;
code = hresult;
if (hresult == S_OK)
{
super("Nothing wrong (S_OK)", file, line);
return;
}
string error = "HRESULT Fail for " ~ what ~ ": ";
wstring info = windowsMessage;
if (info.length)
error ~= info.to!string ~ " ";
super(error ~ "Code 0x" ~ hresult.to!string(16),
file, line);
}
wstring windowsMessage()
{
import std.string : strip;
wchar* message;
auto len = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
null, code, MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT),
cast(wchar*)&message, 0, null);
wstring ret = message[0 .. len].strip.idup;
LocalFree(message);
return ret;
}
HRESULT code;
}
// COM interface defintions (see C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um\WbemCli.Idl)
// [object, restricted, local, uuid(dc12a687-737f-11cf-884d-00aa004b2e24),
// pointer_default(unique)]
//dfmt off
interface IWbemLocator : IUnknown
{
HRESULT ConnectServer(
const BSTR strNetworkResource,
const BSTR strUser,
const BSTR strPassword,
const BSTR strLocale,
c_long lSecurityFlags,
const BSTR strAuthority,
IWbemContext pCtx,
IWbemServices* ppNamespace
);
}
// [object, restricted, local, uuid(44aca674-e8fc-11d0-a07c-00c04fb68820)]
interface IWbemContext : IUnknown
{
HRESULT Clone(IWbemContext* ppNewCopy);
HRESULT GetNames(
c_long lFlags,
BSTR* pNames
);
HRESULT BeginEnumeration(c_long lFlags);
HRESULT Next(
c_long lFlags,
BSTR* pstrName,
VARIANT* pValue
);
HRESULT EndEnumeration();
HRESULT SetValue(
LPCWSTR wszName,
c_long lFlags,
VARIANT* pValue
);
HRESULT GetValue(
LPCWSTR wszName,
c_long lFlags,
VARIANT* pValue
);
HRESULT DeleteValue(
LPCWSTR wszName,
c_long lFlags
);
HRESULT DeleteAll();
};
// [object, restricted, uuid(9556dc99-828c-11cf-a37e-00aa003240c7),
// pointer_default(unique)]
interface IWbemServices : IUnknown
{
// Context.
// ========
HRESULT OpenNamespace(
const BSTR strNamespace,
c_long lFlags,
IWbemContext pCtx,
IWbemServices* ppWorkingNamespace,
IWbemCallResult* ppResult
);
HRESULT CancelAsyncCall(
IWbemObjectSink pSink
);
HRESULT QueryObjectSink(
c_long lFlags,
IWbemObjectSink* ppResponseHandler
);
// Classes and instances.
// ======================
HRESULT GetObject(
const BSTR strObjectPath,
c_long lFlags,
IWbemContext pCtx,
IWbemClassObject* ppObject,
IWbemCallResult* ppCallResult
);
HRESULT GetObjectAsync(
const BSTR strObjectPath,
c_long lFlags,
IWbemContext pCtx,
IWbemObjectSink pResponseHandler
);
// Class manipulation.
// ===================
HRESULT PutClass(
IWbemClassObject pObject,
c_long lFlags,
IWbemContext pCtx,
IWbemCallResult* ppCallResult
);
HRESULT PutClassAsync(
IWbemClassObject pObject,
c_long lFlags,
IWbemContext pCtx,
IWbemObjectSink pResponseHandler
);
HRESULT DeleteClass(
const BSTR strClass,
c_long lFlags,
IWbemContext pCtx,
IWbemCallResult* ppCallResult
);
HRESULT DeleteClassAsync(
const BSTR strClass,
c_long lFlags,
IWbemContext pCtx,
IWbemObjectSink pResponseHandler
);
HRESULT CreateClassEnum(
const BSTR strSuperclass,
c_long lFlags,
IWbemContext pCtx,
IEnumWbemClassObject* ppEnum
);
HRESULT CreateClassEnumAsync(
const BSTR strSuperclass,
c_long lFlags,
IWbemContext pCtx,
IWbemObjectSink pResponseHandler
);
// Instances.
// ==========
HRESULT PutInstance(
IWbemClassObject pInst,
c_long lFlags,
IWbemContext pCtx,
IWbemCallResult* ppCallResult
);
HRESULT PutInstanceAsync(
IWbemClassObject pInst,
c_long lFlags,
IWbemContext pCtx,
IWbemObjectSink pResponseHandler
);
HRESULT DeleteInstance(
const BSTR strObjectPath,
c_long lFlags,
IWbemContext pCtx,
IWbemCallResult* ppCallResult
);
HRESULT DeleteInstanceAsync(
const BSTR strObjectPath,
c_long lFlags,
IWbemContext pCtx,
IWbemObjectSink pResponseHandler
);
HRESULT CreateInstanceEnum(
const BSTR strFilter, // allow more things than a class name
c_long lFlags,
IWbemContext pCtx,
IEnumWbemClassObject* ppEnum
);
HRESULT CreateInstanceEnumAsync(
const BSTR strFilter, // allow more things than a class name
c_long lFlags,
IWbemContext pCtx,
IWbemObjectSink pResponseHandler
);
// Queries.
// ========
HRESULT ExecQuery(
const BSTR strQueryLanguage,
const BSTR strQuery,
c_long lFlags,
IWbemContext pCtx,
IEnumWbemClassObject* ppEnum
);
HRESULT ExecQueryAsync(
const BSTR strQueryLanguage,
const BSTR strQuery,
c_long lFlags,
IWbemContext pCtx,
IWbemObjectSink pResponseHandler
);
HRESULT ExecNotificationQuery(
const BSTR strQueryLanguage,
const BSTR strQuery,
c_long lFlags,
IWbemContext pCtx,
IEnumWbemClassObject* ppEnum
);
HRESULT ExecNotificationQueryAsync(
const BSTR strQueryLanguage,
const BSTR strQuery,
c_long lFlags,
IWbemContext pCtx,
IWbemObjectSink pResponseHandler
);
// Methods
// =======
HRESULT ExecMethod(
const BSTR strObjectPath,
const BSTR strMethodName,
c_long lFlags,
IWbemContext pCtx,
IWbemClassObject pInParams,
IWbemClassObject* ppOutParams,
IWbemCallResult* ppCallResult
);
HRESULT ExecMethodAsync(
const BSTR strObjectPath,
const BSTR strMethodName,
c_long lFlags,
IWbemContext pCtx,
IWbemClassObject pInParams,
IWbemObjectSink pResponseHandler
);
}
// [object, restricted, uuid(44aca675-e8fc-11d0-a07c-00c04fb68820)]
interface IWbemCallResult : IUnknown
{
HRESULT GetResultObject(
c_long lTimeout,
IWbemClassObject* ppResultObject
);
HRESULT GetResultString(
c_long lTimeout,
BSTR* pstrResultString
);
HRESULT GetResultServices(
c_long lTimeout,
IWbemServices* ppServices
);
HRESULT GetCallStatus(
c_long lTimeout,
c_long* plStatus
);
}
// [object, restricted, uuid(7c857801-7381-11cf-884d-00aa004b2e24)]
interface IWbemObjectSink : IUnknown
{
HRESULT Indicate(
c_long lObjectCount,
IWbemClassObject* apObjArray
);
HRESULT SetStatus(
c_long lFlags,
HRESULT hResult,
BSTR strParam,
IWbemClassObject pObjParam
);
}
// [local, restricted, object, uuid(dc12a681-737f-11cf-884d-00aa004b2e24)]
interface IWbemClassObject : IUnknown
{
HRESULT GetQualifierSet(
IWbemQualifierSet* ppQualSet
);
HRESULT Get(
LPCWSTR wszName,
c_long lFlags,
VARIANT* pVal,
CIMTYPE* pType,
c_long* plFlavor
);
HRESULT Put(
LPCWSTR wszName,
c_long lFlags,
VARIANT* pVal,
CIMTYPE Type
);
HRESULT Delete(
LPCWSTR wszName
);
HRESULT GetNames(
LPCWSTR wszQualifierName,
c_long lFlags,
VARIANT* pQualifierVal,
BSTR* pNames
);
HRESULT BeginEnumeration(c_long lEnumFlags);
HRESULT Next(
c_long lFlags,
BSTR* strName,
VARIANT* pVal,
CIMTYPE* pType,
c_long* plFlavor
);
HRESULT EndEnumeration();
HRESULT GetPropertyQualifierSet(
LPCWSTR wszProperty,
IWbemQualifierSet* ppQualSet
);
HRESULT Clone(
IWbemClassObject* ppCopy
);
HRESULT GetObjectText(
c_long lFlags,
BSTR* pstrObjectText
);
HRESULT SpawnDerivedClass(
c_long lFlags,
IWbemClassObject* ppNewClass
);
HRESULT SpawnInstance(
c_long lFlags,
IWbemClassObject* ppNewInstance
);
HRESULT CompareTo(
c_long lFlags,
IWbemClassObject pCompareTo
);
HRESULT GetPropertyOrigin(
LPCWSTR wszName,
BSTR* pstrClassName
);
HRESULT InheritsFrom(
LPCWSTR strAncestor
);
// Method manipulation.
// ====================
HRESULT GetMethod(
LPCWSTR wszName,
c_long lFlags,
IWbemClassObject* ppInSignature,
IWbemClassObject* ppOutSignature
);
HRESULT PutMethod(
LPCWSTR wszName,
c_long lFlags,
IWbemClassObject pInSignature,
IWbemClassObject pOutSignature
);
HRESULT DeleteMethod(
LPCWSTR wszName
);
HRESULT BeginMethodEnumeration(c_long lEnumFlags);
HRESULT NextMethod(
c_long lFlags,
BSTR* pstrName,
IWbemClassObject* ppInSignature,
IWbemClassObject* ppOutSignature
);
HRESULT EndMethodEnumeration();
HRESULT GetMethodQualifierSet(
LPCWSTR wszMethod,
IWbemQualifierSet* ppQualSet
);
HRESULT GetMethodOrigin(
LPCWSTR wszMethodName,
BSTR* pstrClassName
);
}
// [object, restricted, uuid(027947e1-d731-11ce-a357-000000000001)]
interface IEnumWbemClassObject : IUnknown
{
HRESULT Reset();
HRESULT Next(
c_long lTimeout,
ULONG uCount,
IWbemClassObject* apObjects,
ULONG* puReturned
);
HRESULT NextAsync(
ULONG uCount,
IWbemObjectSink pSink
);
HRESULT Clone(
IEnumWbemClassObject* ppEnum
);
HRESULT Skip(
c_long lTimeout,
ULONG nCount
);
}
// [object, restricted, local, uuid(dc12a680-737f-11cf-884d-00aa004b2e24)]
interface IWbemQualifierSet : IUnknown
{
HRESULT Get(
LPCWSTR wszName,
c_long lFlags,
VARIANT* pVal,
c_long* plFlavor
);
HRESULT Put(
LPCWSTR wszName,
VARIANT* pVal,
c_long lFlavor
);
HRESULT Delete(
LPCWSTR wszName
);
HRESULT GetNames(
c_long lFlags,
BSTR* pNames
);
HRESULT BeginEnumeration(
c_long lFlags
);
HRESULT Next(
c_long lFlags,
BSTR* pstrName,
VARIANT* pVal,
c_long* plFlavor
);
HRESULT EndEnumeration();
}
//dfmt on
enum CIMTYPE : c_long
{
CIM_ILLEGAL = 0xfff,
CIM_EMPTY = 0,
CIM_SINT8 = 16,
CIM_UINT8 = 17,
CIM_SINT16 = 2,
CIM_UINT16 = 18,
CIM_SINT32 = 3,
CIM_UINT32 = 19,
CIM_SINT64 = 20,
CIM_UINT64 = 21,
CIM_REAL32 = 4,
CIM_REAL64 = 5,
CIM_BOOLEAN = 11,
CIM_STRING = 8,
CIM_DATETIME = 101,
CIM_REFERENCE = 102,
CIM_CHAR16 = 103,
CIM_OBJECT = 13,
CIM_FLAG_ARRAY = 0x2000
}
enum WBEM_FLAG_RETURN_IMMEDIATELY = 0x10;
enum WBEM_FLAG_RETURN_WBEM_COMPLETE = 0;
enum WBEM_FLAG_BIDIRECTIONAL = 0;
enum WBEM_FLAG_FORWARD_ONLY = 0x20;
enum WBEM_FLAG_NO_ERROR_OBJECT = 0x40;
enum WBEM_FLAG_RETURN_ERROR_OBJECT = 0;
enum WBEM_FLAG_SEND_STATUS = 0x80;
enum WBEM_FLAG_DONT_SEND_STATUS = 0;
enum WBEM_FLAG_ENSURE_LOCATABLE = 0x100;
enum WBEM_FLAG_DIRECT_READ = 0x200;
enum WBEM_FLAG_SEND_ONLY_SELECTED = 0;
// backward-compatibility
enum WBEM_RETURN_WHEN_COMPLETE = 0;
enum WBEM_RETURN_IMMEDIATELY = 0x10;
// these bits are reserved!!
enum WBEM_MASK_RESERVED_FLAGS = 0x1F000;
enum WBEM_FLAG_USE_AMENDED_QUALIFIERS = 0x20000;
// If used, the context object must have one or more of the following
// BOOL "INCLUDE_OWNER"
// BOOL "INCLUDE_DACL"
// BOOL "INCLUDE_SACL"
// BOOL "INCLUDE_GROUP"
enum WBEM_FLAG_STRONG_VALIDATION = 0x100000;
enum WBEM_NO_WAIT = 0;
enum WBEM_INFINITE = 0xFFFFFFFF;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment