1
Vote

Custom/derived forms are not being called from base forms

description

Issue Description:
The OEM deployment code contains base forms that handle the bulk of the operation, and each OEM takes the base form and inherits it / derives their own form to do customization of strings, logos, and other things. When ConfigMgr calls a form from the task sequence editor or from a right-click action, it's calling the derived form, not the base form. However, once that form is instantiated, subsequent calls to additional forms do not call the derived versions - they call the base forms. For example, the task sequence editor loads a customized step dialog from "TaskSequenceAction_Extension.cs", which is derived from "TaskSequenceAction.cs". The developer has also derived "CreateTaskSequenceDialog_Extension.cs" from "CreateTaskSequenceDialog.cs". However, when the code needs to load the CreateTaskSequenceDialog code, it loads the base form, not the derived form. When the user selects the right-click action to create a new TS, ConfigMgr loads the derived form, not the base form. This leads to inconsistent behavior, potentially incorrect configuration of task sequences, and generally user confusion.
 
Solution Description:
In order to call the appropriate derived form (if there is one), the code needs to use Reflection to dynamically load the class and instantiate the form. Because the class type is not known at build time, the code must also use dynamic property assignment and retrieval using Reflection. The names of the classes to load would be defined in string resources, and when the base derived form is loaded, any changes to the strings will result in different forms being loaded instead of the base forms.
 
Here is the suggested changes that would occur to enable this functionality:
  1. Base code changes:
       a. Add new string resources to the base projects (OemDeployment and CustomReboot) that contain method names for the forms, dialogs, etc. to be called.
            i. Class_CreateTaskSequenceDialog = “CreateTaskSequenceDialog”
            ii. Class_ApplyDialog = “ApplyDialog”
            iii. Class_TextEditor = ”TextEditor”
            iv. Class_ArrayBuilder = “ArrayBuilder.ArrayBuilderDialog”
            v. Class_FileViewer = “FileViewer”
            vi. Class_XMessageBox = “XMessageBox”
     
        b. Modify method calls for the above to use reflection instead of the static class names to dynamically invoke the method and get/set properties.
            This will be done through the addition of three new methods:
     
                i. public static Object CreateObjectInstance(string classFullName, Object[] classParameters)
     
                ii. public static bool SetDynamicProperty(Object myObject, string propertyName, Object propertyValue)
     
                iii. public static Object GetDynamicProperty(Object myObject, string propertyName)
     
            ...and through modification of the current instantiation & property-setting code, similar to the below:
     
            //(old code) CreateTaskSequenceDialog cts = new CreateTaskSequenceDialog(Connection, currentSequenceXml, BaseRegistryKey64, templateFileName);
            Object[] classParams = new Object[4] { Connection, currentSequenceXml, BaseRegistryKey64, templateFileName };
            Object cts = IntegrationKitUtilities.CreateObjectInstance(Properties.Resources.Class_CreateTaskSequenceDialog, classParams);
            if (IntegrationKitUtilities.SetDynamicProperty(cts, "SelectedTaskSequenceName", tsName) == false)
            {
                    MessageBox.Show("An error occurred trying to set the task sequence name.");
                    return;
            }
            // ...other code here...
            MethodInfo ctsDialog = ctsType.GetMethod("ShowDialog");
            DialogResult ctsRes = (DialogResult)ctsDialog.Invoke(cts, null);
     
     
  2. Changes to OEM code (derived forms):
        a. For those forms where you want to override any properties, you would:
            i. Create a new inherited form instance, similar to your existing inherited forms like About_Extension.cs
            ii. Add new resource strings in your main inherited form that is calling the additional forms that override the strings above with your new class name
            iii. Add new resource strings as needed to change the form’s properties (within the inherited form instance)

comments

wrote Dec 17, 2009 at 10:40 PM

Note: The current workaround suggested is to modify your copy of the common code to call your specific sub-form. I have considered implementing reflection but the solution ends up being a testing nightmare, and being a single contributor to this project, it's not feasible to accomplish this task. If someone has alternative suggestions to resolving this issue, I'll be happy to hear them. I will continue to leave this issue open for visibility, but I do not have any current plans for resolving this.

wrote Feb 13, 2013 at 10:45 PM