static ManagementSession() { ManagementSession._factories = new Dictionary <string, object>(); ManagementSession._factoryTypes = new Dictionary <string, Type>(); ManagementSession._classTypes = new Dictionary <string, Type>(); ManagementSession.assemblyName = new AssemblyName("ManagementClassDynamicImplementations"); ManagementSession.assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(ManagementSession.assemblyName, AssemblyBuilderAccess.RunAndSave); #if DEBUG Type debugType = typeof(DebuggableAttribute); ConstructorInfo debugConInfo = debugType.GetConstructor(new[] { typeof(DebuggableAttribute.DebuggingModes) }); CustomAttributeBuilder debugAttrBuilder = new CustomAttributeBuilder(debugConInfo, new object[] { DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.Default }); ManagementSession.assemblyBuilder.SetCustomAttribute(debugAttrBuilder); bool debugSymbols = true; #else bool debugSymbols = false; #endif ManagementSession.moduleBuilder = ManagementSession.assemblyBuilder.DefineDynamicModule(ManagementSession.assemblyName.Name, ManagementSession.assemblyName.Name + ".dll", debugSymbols); ManagementSessionDebugUtilities.DefineDocument(ManagementSession.moduleBuilder); }
// Handle classes private static Type CreateClassType(Type classDefType) { string classTypeName = $"Impl_{classDefType.Name}"; if (!classDefType.IsSubclassOf(typeof(ManagementClassBase))) { throw new Exception($"'{classDefType.Name}' does not inherit from '{nameof(ManagementClassBase)}'"); } string mgmtNamespacePath = ManagementSession.GetNamespacePath(classDefType); string mgmtClassName = ManagementSession.GetClassName(classDefType); ManagementClass mgmtClass = new ManagementClass(mgmtNamespacePath, mgmtClassName, null); TypeBuilder classType = ManagementSession.moduleBuilder.DefineType(classTypeName, TypeAttributes.Class | TypeAttributes.NotPublic, classDefType); BindingFlags defaultBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; // Predefined method info MethodInfo getManagementObject = classDefType.GetMethod("get_ManagementObject", BindingFlags.Instance | BindingFlags.NonPublic); MethodInfo getManagementBaseObjectProperties = typeof(ManagementBaseObject).GetMethod("get_Properties", BindingFlags.Instance | BindingFlags.Public); MethodInfo getPropertyDataCollectionItem = typeof(PropertyDataCollection).GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public); MethodInfo getPropertyDataValue = typeof(PropertyData).GetMethod("get_Value", BindingFlags.Instance | BindingFlags.Public); MethodInfo setPropertyDataValue = typeof(PropertyData).GetMethod("set_Value", BindingFlags.Instance | BindingFlags.Public); // Implement default constructor ConstructorBuilder defaultConstructor = classType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] { typeof(ManagementBaseObject) }); ILGenerator constructorIl = defaultConstructor.GetILGenerator(); // Define parameter defaultConstructor.DefineParameter(1, ParameterAttributes.None, "managementObject"); ManagementSessionDebugUtilities.MarkPoint(constructorIl); constructorIl.Emit(OpCodes.Ldarg_0); constructorIl.Emit(OpCodes.Ldarg_1); constructorIl.Emit(OpCodes.Call, classDefType.GetConstructor(new[] { typeof(ManagementBaseObject) })); constructorIl.Emit(OpCodes.Ret); // Implement properties IEnumerable <PropertyInfo> propertiesToImplement = classDefType.GetProperties(defaultBindingFlags); foreach (PropertyInfo propertyInfo in propertiesToImplement) { // Get real property name and type ManagementPropertyAttribute propertyAttribute = propertyInfo.GetCustomAttribute(typeof(ManagementPropertyAttribute)) as ManagementPropertyAttribute; string realPropertyName = propertyAttribute?.Name ?? propertyInfo.Name; Type realPropertyType = propertyInfo.PropertyType; if (realPropertyType.IsEnum) { realPropertyType = realPropertyType.GetEnumUnderlyingType(); } else if (realPropertyType == typeof(DateTime)) { realPropertyType = typeof(String); } realPropertyType = propertyAttribute?.CastAs ?? realPropertyType; // Check if underlying management object has property bool propertyExists = false; try { if (mgmtClass.Properties[realPropertyName] != null) { propertyExists = true; } } catch (ManagementException e) { if (e.ErrorCode != ManagementStatus.NotFound) { throw e; } } // Get property getter string propertyGetterName = $"get_{propertyInfo.Name}"; MethodInfo getterMethodInfo = classDefType.GetMethod(propertyGetterName, defaultBindingFlags); bool implementGetter = getterMethodInfo != null && getterMethodInfo.IsAbstract; // Get property setter string propertySetterName = $"set_{propertyInfo.Name}"; MethodInfo setterMethodInfo = classDefType.GetMethod(propertySetterName, defaultBindingFlags); bool implementSetter = setterMethodInfo != null && setterMethodInfo.IsAbstract; string propertyNotExistMessage = $"'{mgmtNamespacePath}:{mgmtClassName}' does not have property '{realPropertyName}"; Debug.WriteLineIf((implementGetter || implementSetter) && !propertyExists, $"WARNING: {propertyNotExistMessage}"); // Declare property if needed if (implementGetter || implementSetter) { PropertyBuilder propertyBuilder = classType.DefineProperty(propertyInfo.Name, propertyInfo.Attributes, propertyInfo.PropertyType, null); if (implementGetter) { MethodBuilder getterMethodBuilder = classType.DefineMethod(propertyGetterName, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyInfo.PropertyType, null); ILGenerator il = getterMethodBuilder.GetILGenerator(); if (propertyExists) { if (propertyInfo.PropertyType.IsSubclassOf(typeof(ManagementClassBase)) && mgmtClass.Properties[realPropertyName].Type != CimType.Reference) // Verify CIM/WMI return type is a reference if property return type is a ManagementClassBase type { string err = $"'{mgmtNamespacePath}:{mgmtClassName}'.'{realPropertyName}' is not a {nameof(CimType.Reference)} type."; ManagementSessionDebugUtilities.MarkPoint(il); il.Emit(OpCodes.Ldstr, err); il.Emit(OpCodes.Newobj, typeof(InvalidCastException).GetConstructor(new[] { typeof(String) })); il.Emit(OpCodes.Throw); Debug.WriteLine($"WARNING: {err}"); } else if (propertyInfo.PropertyType == typeof(DateTime) && mgmtClass.Properties[realPropertyName].Type != CimType.DateTime) // Verify it's a DateTime type { string err = $"'{mgmtNamespacePath}:{mgmtClassName}'.'{realPropertyName}' is not a {nameof(CimType.DateTime)} type."; ManagementSessionDebugUtilities.MarkPoint(il); il.Emit(OpCodes.Ldstr, err); il.Emit(OpCodes.Newobj, typeof(InvalidCastException).GetConstructor(new[] { typeof(String) })); il.Emit(OpCodes.Throw); Debug.WriteLine($"WARNING: {err}"); } else { ManagementSessionDebugUtilities.MarkPoint(il); // Get management object il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, getManagementObject); // Get property - will always exist, checked above il.Emit(OpCodes.Callvirt, getManagementBaseObjectProperties); il.Emit(OpCodes.Ldstr, realPropertyName); il.Emit(OpCodes.Callvirt, getPropertyDataCollectionItem); il.Emit(OpCodes.Callvirt, getPropertyDataValue); // Check if value is null Label returnNull = il.DefineLabel(); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse_S, returnNull); ManagementSession.EmitConvertTo(il, realPropertyType, propertyInfo.PropertyType, getManagementObject); il.Emit(OpCodes.Ret); // Property doesn't exist, return null il.MarkLabel(returnNull); il.Emit(OpCodes.Pop); ManagementSession.EmitGetDefault(il, propertyInfo.PropertyType); il.Emit(OpCodes.Ret); } } else { ManagementSessionDebugUtilities.MarkPoint(il); il.Emit(OpCodes.Ldstr, propertyNotExistMessage); il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(new[] { typeof(String) })); il.Emit(OpCodes.Throw); } propertyBuilder.SetGetMethod(getterMethodBuilder); } if (implementSetter) { MethodBuilder setterMethodBuilder = classType.DefineMethod(propertySetterName, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(void), new[] { propertyInfo.PropertyType }); ILGenerator il = setterMethodBuilder.GetILGenerator(); if (propertyExists) { if (propertyInfo.PropertyType.IsSubclassOf(typeof(ManagementClassBase)) && mgmtClass.Properties[realPropertyName].Type != CimType.Reference) // Verify CIM/WMI return type is a reference if property return type is a ManagementClassBase type { string err = $"'{mgmtNamespacePath}:{mgmtClassName}'.'{realPropertyName}' is not a {nameof(CimType.Reference)} type."; ManagementSessionDebugUtilities.MarkPoint(il); il.Emit(OpCodes.Ldstr, err); il.Emit(OpCodes.Newobj, typeof(InvalidCastException).GetConstructor(new[] { typeof(String) })); il.Emit(OpCodes.Throw); Debug.WriteLine($"WARNING: {err}"); } else if (propertyInfo.PropertyType == typeof(DateTime) && mgmtClass.Properties[realPropertyName].Type != CimType.DateTime) // Verify it's a DateTime type { string err = $"'{mgmtNamespacePath}:{mgmtClassName}'.'{realPropertyName}' is not a {nameof(CimType.DateTime)} type."; ManagementSessionDebugUtilities.MarkPoint(il); il.Emit(OpCodes.Ldstr, err); il.Emit(OpCodes.Newobj, typeof(InvalidCastException).GetConstructor(new[] { typeof(String) })); il.Emit(OpCodes.Throw); Debug.WriteLine($"WARNING: {err}"); } else { ManagementSessionDebugUtilities.MarkPoint(il); // Get management object il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, getManagementObject); // Get property - will always exist, checked above il.Emit(OpCodes.Callvirt, getManagementBaseObjectProperties); il.Emit(OpCodes.Ldstr, realPropertyName); il.Emit(OpCodes.Callvirt, getPropertyDataCollectionItem); // Get value il.Emit(OpCodes.Ldarg_1); ManagementSession.EmitConvertFrom(il, propertyInfo.PropertyType, realPropertyType); // Set property value il.Emit(OpCodes.Callvirt, setPropertyDataValue); // Return value il.Emit(OpCodes.Ret); } } else { ManagementSessionDebugUtilities.MarkPoint(il); il.Emit(OpCodes.Ldstr, propertyNotExistMessage); il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(new[] { typeof(String) })); il.Emit(OpCodes.Throw); } propertyBuilder.SetSetMethod(setterMethodBuilder); } } } // Implement methods IEnumerable <MethodInfo> methodsToImplement = classDefType.GetMethods(defaultBindingFlags).Where(m => m.IsAbstract && !m.IsSpecialName); foreach (MethodInfo methodInfo in methodsToImplement) { // Get real method name, return property name, and real return type ManagementPropertyAttribute methodAttribute = methodInfo.GetCustomAttribute(typeof(ManagementPropertyAttribute)) as ManagementPropertyAttribute; ManagementPropertyAttribute returnAttribute = methodInfo.ReturnTypeCustomAttributes.GetCustomAttributes(typeof(ManagementPropertyAttribute), false).OfType <ManagementPropertyAttribute>().FirstOrDefault(); string realMethodName = methodAttribute?.Name ?? methodInfo.Name; string returnPropertyName = returnAttribute?.Name; Type returnPropertyType = returnAttribute?.CastAs ?? methodInfo.ReturnType; ManagementBaseObject mgmtInParams = null; try { mgmtInParams = mgmtClass.GetMethodParameters(realMethodName); } catch (ManagementException e) { if (e.ErrorCode != ManagementStatus.MethodNotImplemented) { throw e; } } ParameterInfo[] paramInfos = methodInfo.GetParameters(); MethodBuilder methodBuilder = classType.DefineMethod(methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual, methodInfo.ReturnType, paramInfos.Select(p => p.ParameterType).ToArray()); ILGenerator il = methodBuilder.GetILGenerator(); if (mgmtInParams == null) { string err = $"'{mgmtNamespacePath}:{mgmtClassName}' does not have method '{realMethodName}'"; il.Emit(OpCodes.Ldstr, err); il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetConstructor(new[] { typeof(String) })); il.Emit(OpCodes.Throw); Debug.WriteLine($"WARNING: {err}"); continue; } LocalBuilder inParams = il.DeclareLocal(typeof(ManagementBaseObject)); if (!paramInfos.Where(p => !p.IsOut).Any()) { // No parameters il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stloc_S, inParams); } else { // Get method parameters, store in 'inParams' il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, getManagementObject); il.Emit(OpCodes.Ldstr, realMethodName); il.Emit(OpCodes.Call, typeof(ManagementObject).GetMethod("GetMethodParameters", BindingFlags.Instance | BindingFlags.Public)); il.Emit(OpCodes.Stloc_S, inParams); for (int paramIndex = 0; paramIndex < paramInfos.Length; paramIndex++) { ParameterInfo paramInfo = paramInfos[paramIndex]; #if DEBUG // Define parameter name methodBuilder.DefineParameter(paramIndex + 1, paramInfo.Attributes, paramInfo.Name); #endif if (paramInfo.IsOut) { continue; } // Get property name and real type ManagementPropertyAttribute paramAttribute = paramInfo.GetCustomAttribute(typeof(ManagementPropertyAttribute)) as ManagementPropertyAttribute; string realParamPropertyName = paramAttribute?.Name ?? paramInfo.Name; Type realParamPropertyType = paramAttribute?.CastAs ?? (paramInfo.ParameterType.IsEnum ? Enum.GetUnderlyingType(paramInfo.ParameterType) : paramInfo.ParameterType); bool paramExists = false; try { if (mgmtInParams.Properties[realParamPropertyName] != null) { paramExists = true; } } catch (ManagementException e) { if (e.ErrorCode != ManagementStatus.NotFound) { throw e; } } if (!paramExists) { string err = $"'{mgmtNamespacePath}:{mgmtClassName}'.'{realMethodName}' does not have parameter '{realParamPropertyName}'"; Debug.WriteLine($"WARNING: {err}"); continue; } // Get property - will always exist, checked above il.Emit(OpCodes.Ldloc_S, inParams); il.Emit(OpCodes.Callvirt, getManagementBaseObjectProperties); il.Emit(OpCodes.Ldstr, realParamPropertyName); il.Emit(OpCodes.Callvirt, getPropertyDataCollectionItem); // Get argument, ldarg.0 = this il.Emit(OpCodes.Ldarg_S, paramIndex + 1); if (paramInfo.ParameterType.IsByRef) { il.Emit(OpCodes.Ldind_Ref); } Type underlyingParamType = paramInfo.ParameterType.IsByRef ? paramInfo.ParameterType.GetElementType() : paramInfo.ParameterType; ManagementSession.EmitConvertFrom(il, underlyingParamType, realParamPropertyType); // Set property value il.Emit(OpCodes.Callvirt, setPropertyDataValue); } } LocalBuilder outParams = il.DeclareLocal(typeof(ManagementBaseObject)); // outParams = this.ManagementObject.InvokeMethod(realMethodName, inParams, null) il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Call, getManagementObject); il.Emit(OpCodes.Ldstr, realMethodName); il.Emit(OpCodes.Ldloc_S, inParams); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Callvirt, typeof(ManagementObject).GetMethod("InvokeMethod", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(String), typeof(ManagementBaseObject), typeof(InvokeMethodOptions) }, null)); il.Emit(OpCodes.Stloc_S, outParams); // Get error code il.Emit(OpCodes.Ldloc_S, outParams); il.Emit(OpCodes.Callvirt, getManagementBaseObjectProperties); il.Emit(OpCodes.Ldstr, "ReturnValue"); il.Emit(OpCodes.Callvirt, getPropertyDataCollectionItem); il.Emit(OpCodes.Callvirt, getPropertyDataValue); il.Emit(OpCodes.Unbox_Any, typeof(UInt32)); // Check if error code != 0 Label invokeSuccess = il.DefineLabel(); il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse_S, invokeSuccess); // Throw error il.Emit(OpCodes.Call, typeof(Marshal).GetMethod("ThrowExceptionForHR", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(Int32) }, null)); if (methodInfo.ReturnType != typeof(void)) { il.Emit(OpCodes.Ldnull); } il.Emit(OpCodes.Ret); // No error il.MarkLabel(invokeSuccess); il.Emit(OpCodes.Pop); // Handle out parameters for (int paramIndex = 0; paramIndex < paramInfos.Length; paramIndex++) { ParameterInfo paramInfo = paramInfos[paramIndex]; if (!paramInfo.ParameterType.IsByRef) { continue; } // Get property name and real type ManagementPropertyAttribute paramAttribute = paramInfo.GetCustomAttribute(typeof(ManagementPropertyAttribute)) as ManagementPropertyAttribute; string realParamPropertyName = paramAttribute?.Name ?? paramInfo.Name; Type underlyingParamType = paramInfo.ParameterType.GetElementType(); Type realParamPropertyType = paramAttribute?.CastAs ?? (underlyingParamType.IsEnum ? Enum.GetUnderlyingType(underlyingParamType) : underlyingParamType); il.Emit(OpCodes.Ldloc_S, outParams); il.Emit(OpCodes.Callvirt, getManagementBaseObjectProperties); il.Emit(OpCodes.Ldstr, realParamPropertyName); il.Emit(OpCodes.Callvirt, getPropertyDataCollectionItem); Label propertyIsNull = il.DefineLabel(); Label propertyIsNotNull = il.DefineLabel(); // Check if property exists il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse_S, propertyIsNull); // Property exists il.Emit(OpCodes.Callvirt, getPropertyDataValue); ManagementSession.EmitConvertTo(il, realParamPropertyType, underlyingParamType, getManagementObject); if (underlyingParamType.IsValueType) { il.Emit(OpCodes.Box, underlyingParamType); } LocalBuilder returnValue = il.DeclareLocal(underlyingParamType); // By ref values il.Emit(OpCodes.Stloc_S, returnValue); il.Emit(OpCodes.Ldarg_S, paramIndex + 1); // Address il.Emit(OpCodes.Ldloc_S, returnValue); // Value il.Emit(OpCodes.Stind_Ref); // Store value at address il.Emit(OpCodes.Br_S, propertyIsNotNull); // Property doesn't exist il.MarkLabel(propertyIsNull); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldstr, $"'{mgmtNamespacePath}:{mgmtClassName}'.'{realMethodName}' does not return property '{realParamPropertyName}'"); il.Emit(OpCodes.Newobj, typeof(ArgumentException).GetConstructor(new[] { typeof(String) })); il.Emit(OpCodes.Throw); il.MarkLabel(propertyIsNotNull); } if (methodInfo.ReturnType != typeof(void)) { il.Emit(OpCodes.Ldloc_S, outParams); il.Emit(OpCodes.Callvirt, getManagementBaseObjectProperties); il.Emit(OpCodes.Ldstr, returnPropertyName); il.Emit(OpCodes.Callvirt, getPropertyDataCollectionItem); Label returnPropertyIsNull = il.DefineLabel(); // Check if property exists il.Emit(OpCodes.Dup); il.Emit(OpCodes.Brfalse_S, returnPropertyIsNull); // Property exists il.Emit(OpCodes.Callvirt, getPropertyDataValue); ManagementSession.EmitConvertTo(il, returnPropertyType, methodInfo.ReturnType, getManagementObject); il.Emit(OpCodes.Ret); // Property doesn't exist il.MarkLabel(returnPropertyIsNull); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldstr, $"'{mgmtNamespacePath}:{mgmtClassName}'.'{realMethodName}' does not return property '{returnPropertyName}'"); il.Emit(OpCodes.Newobj, typeof(ArgumentException).GetConstructor(new[] { typeof(String) })); il.Emit(OpCodes.Throw); } else { il.Emit(OpCodes.Ret); } } return(classType.CreateType()); }