My last article ("Customizing Systems Management Server," January 1997) explained how you add custom inventory groups and architectures (inventory items) to the Systems Management Server (SMS) inventory with Management Information Format (MIF) files. This article shows how to polish your SMS inventory by creating custom graphics to represent the custom inventory objects, such as a printer. Once you learn how to name resources so that SMS can access them, you can build and register a custom DLL that contains the custom graphics SMS will use. Creating these custom graphics requires some coding, but as you'll see, you don't need to be a programmer to accomplish this simple task, especially if you have a modern development tool such as Microsoft Visual C++ (VC++).
Customizing Bitmaps and Icons in SMS Administrator
SMS uses standard bitmaps and icons to identify custom inventory objects. So, after you create a custom architecture object, it appears as a default bitmap in the SMS Administrator Sites window. For example, the custom Printer architecture I created for the January article appears as the default bitmap for HP Printer 1, as you see in Screen 1.
Whereas custom architectures appear as bitmaps, custom groups appear as icons. By opening the Properties window for HP Printer 1, you see the icons shown in Screen 2. In this screen, the custom printer groups appear as default SMS icons. Unfortunately, these generic graphics don't illustrate the nature of the objects.
Ideally, you want the graphics to reflect the type of inventory objects they represent. Fortunately, you can display custom bitmaps and icons for new custom groups or architectures. You override default SMS architecture and group icons by providing SMS with a DLL that contains custom bitmap and icon resources. SMS can then use these resources to represent your custom inventory objects. To tell SMS to use the DLL, you have to add special entries to the Windows NT Registry. Let's look at SMS's requirements for naming graphic resources so you can make them available for SMS use.
Bitmap and Icon Resource Naming for SMS
To display a graphic for an inventory object, SMS first searches custom resource-only DLLs registered with the NT Registry and then searches its standard resources for a bitmap with a resource name of architecture_systemtype_systemrole. If SMS can't find this bitmap, it looks for a resource named architecture_systemrole.
Here, architecture is the name of the inventory object's (i.e., the component's) Architecture group (which defines the component and its attribute structure) in a MIF, systemtype is the value of the SystemType attribute of the component's Identification group (which lists attributes that identify the instance of the component the MIF describes), and systemrole is the value of the SystemRole attribute of the component's Identification group (see my January article for details). So, for example, in Screen 1, HP Printer 1 has an Architecture of Printer, a SystemType of Laser Printer, and a SystemRole of Printer. You can create a specific bitmap resource (PRINTER_LASER_PRINTER_PRINTER) that appears for laser printers such as HP Printer 1 and a general printer bitmap resource (PRINTER_PRINTER) that appears for non-laser printers. Note that SMS treats resource names as uppercase and replaces spaces with underscores.
When you display the properties for a component, each group within the component appears as an icon in the Properties pane on the left side of the Properties window. The exception is the Architecture group in the window title. Screen 2 shows the resulting properties window for the Printer architecture. Notice that the title bar contains "Printer Properties," which identifies the component's architecture.
SMS selects the icon that appears for each group in the Architecture Properties window similarly to how it selects the bitmaps for the SMS Administrator Sites window. For a given group, SMS searches for registered custom resource-only DLLs first and then searches through its standard resources for an icon with the following resource names, respectively:
PDG_systemtype_groupname PDG_architecture_groupname PDG_STD_groupname
Systemtype and architecture have the same meaning for icons as they do for bitmaps, and groupname is the value of the Name property for the group (PDG and STD are fixed prefixes). For the /Screen_0 example in Screen 2, you can create very specific icon resources (PDG_LASER_/Screen_0_/Screen_0_DETAILS and PDG_LASER_/Screen_0_PRINTER_FONTS) because the two groups are Printer Details and Printer Fonts and HP Printer 1 is a Laser Printer. Optionally, you can create more general resources (PDG_PRINTER_PRINTER_DETAILS and PDG_PRINTER_PRINTER_FONTS) or minimally specific resources (PDG_ STD_PRINTER_DETAILS and PDG_STD_PRINTER_FONTS). Let's build and register a custom resource-only DLL that uses a combination of these last two resource options.
Building a Custom DLL
To create a custom DLL with resources, you need to code a C++ file and a resource script file. To learn more about how to code these files, see the sidebar, "Creating Your Own DLL," page 148 which illustrates how to code an example C++ file (smscust.cpp) and resource script (smscust.rc).
You can use a variety of tools to develop your DLL. I used Microsoft VC++ version 4.2 for this example. If you have another C++ tool such as Borland C++, the process will be similar (check your development tool documentation). In VC++, start by creating a project workspace. Perform the following steps:
- Start Microsoft Developer Studio, and choose File, New from the menu.
- Select Project Workspace from the resulting dialog box, and click OK.
- In the New Project Workspace dialog box, select Dynamic-Link Library. In the Name field, type the name of your project (in this case SMSCust). In the Location field, make sure you specify the path where you want VC++ to store the files. Screen 3 shows the resulting dialog box with my entries.
- Click Create. VC++ creates several files for the project and the SMSCust subdirectory, if necessary. You will see a screen similar to Screen 4that shows an empty project workspace. At the bottom of the left pane, notice the tabs labeled ClassView, FileView, and InfoView (the InfoView tab appears only if you open VC++ Books Online). Screen 4 shows the ClassView.
- Create a 16 * 16-pixel printer bitmap, name the file printer.bmp (this filename corresponds to the bitmap name in the smscust.rc resource script file from the sidebar, "Creating Your Own DLL," page 148), and save this bitmap in the SMSCust subdirectory that contains your VC++ project. You can create this bitmap in Microsoft Developer Studio, but I find that creating an initial bitmap using good old Microsoft Paint is easier. Make sure you size the paint space to 16 * 16 pels (i.e., pixels). (Tip: Zoom the picture as big as you can and turn on the grid in Paint to make drawing with a mouse easier.)
- Copy the smscust.cpp C++ file (that you created following the instructions in the sidebar, "Creating Your Own DLL," page 148) to the SMSCust subdirectory. You don't have to copy the smscust.rc file to this directory--let VC++ build one for you.
- From the VC++ Insert menu, select the Insert Files into Project option. Select the smscust.cpp file from the Insert Files into Project dialog box, and click Add.
- Select the FileView tab, and expand the folder. You will see smscust.cpp listed.
- To create the resource script file, select Insert, Resource from the VC++ menu, and click Import in the Insert Resource dialog box. In the resulting Import Resource dialog box, select the printer.bmp bitmap that you created with Microsoft Paint. Click Import to see the Image Editor with the printer bitmap ready for further editing.
- Close the Image Editor window by clicking Close (make sure you click the second-level child window Close button, or you'll close Developer Studio by mistake). Screen 5 shows the imported bitmap.
- Now that you have the bitmap imported, you need to do some cleanup. Notice that the Printer resource is IDB_BITMAP1. This designation represents a number for the real resource name. You need to have a name (instead of a number) that SMS can reference, so you need to rename this symbol and the script file, which in this case defaulted to Script1. Right-click IDB_BITMAP1, and select Properties from the shortcut menu. Rename the resource by setting the ID: field to "PRINTER_PRINTER". (You need to include the quotes in your entry to ensure that VC++ doesn't convert the name into a number.)
- Select File, Save As from the VC++ menu, and save the script file as smscust.rc in the SMSCust directory.
- Select Insert, Files into Project from the VC++ menu, and select Common Files in the Files of Type drop-down list box. You will see two new files in the list (smscust.rc and resource.h). VC++ generated the resource.h file when it built the smscust.rc file. Select the smscust.rc file, and click Add. Close the pane on the right containing the resource script.
- A new tab (the ResourceView tab) will appear at the bottom of the Project window with a graphic that looks like a cactus in the sun. If you select the ResourceView tab and expand the resulting folders, you see a screen similar to Screen 6.
- The drop-down list box on the second toolbar in Screen 6 that shows SMSCust - Win32 Debug means that the DLL contains debug information. You usually don't need to debug a resource-only DLL, so you can select the SMSCust - Win32 Release option from the drop-down list.
- Select Build smscust.dll from the VC++ Build menu to generate the smscust.dll file in a Release subdirectory under the SMSCust subdirectory. You will get 0 error(s) and 0 warning(s) if you leave VC++ in its default warning level 3 setting. Otherwise, you can get some messages about non-ANSI compliance. Ignore these messages.
Registering a Custom Resource-Only DLL
To register a custom DLL for use by SMS, you must add a few keys and values to the NT Registry. At the command prompt, type
regedt32 to open the NT Registry. Click the HKEY_LOCAL_MACHINE\Software\Microsoft\SMS key (NT adds this key when you install SMS), and add a new key, ResDlls.
After you add the ResDlls key, you can add keys under ResDlls for each custom resource-only DLL that you want SMS to reference (you can name these keys anything you want). Within these keys, you add the value PathName of type REG_SZ (a single string) that contains either the full path to the custom resource-only DLL or the DLL's filename if its path is in the PATH environment string. Finally, you add the value Installed of type REG_MULTI_SZ (multiple strings) to the ResDlls key. The strings you add to this value are a list of the keys you created with the PathName for each custom resource-only DLL. The Installed values act like an on-off switch, which is convenient for testing multiple DLLs.
Listing 1 shows an example set of Registry entries in a Registry script file that you can process with regini.exe, a utility from the Microsoft Windows NT Workstation 4.0 Resource Kit. Screen 7 shows the results in the Registry after applying this script file. Notice that the Installed value references only the DLLNum1 and DLLNum2 Registry keys. Therefore, SMS is not using notready.dll.
The SMS Administrator program searches custom resource-only DLLs in reverse of the order in the Installed value. So, in the example, SMS Administrator searches for a named graphic in the following order: myicons.dll, myres.dll, and finally in the SMS default resources.
I listed the Registry entries for this example under the HKEY_LOCAL_MACHINE path. You can make the same entries in HKEY_CURRENT_USER to customize the SMS Administrator graphics by individual user. SMS will search DLLs listed under HKEY_CURRENT_USER first before looking under HKEY_LOCAL_MACHINE.
Installing the Custom Resource-Only DLL
After you build a custom DLL such as smscust.dll, the next step is to get the SMS Administrator to use it. Perform the following steps:
- Create a c:\smsres directory, and copy smscust.dll file into this directory (this step saves you some typing in the Registry and keeps the \smscust project directories separate).
- Make the following entries in the Registry using NT's Regedt32 program: Add the key HKEY_LOCAL_MACHINE\Software\Microsoft\SMS\ResDlls.
In the ResDlls key, add the value Installed as a MULTI_REG_SZ and set the value to SMSCust.
Add the key HKEY_LOCAL_MACHINE\Software\Microsoft\SMS\ResDlls\SMSCust.
In the SMSCust key, add the value PathName as a REG_SZ and set its value to c:\SMSRes\SMSCust.dll.
- If SMS Administrator is running, close it and restart it. SMS Administrator will query the Registry for custom resource-only DLLs when you restart it.
- You will see an SMS Administrator screen similar to what you see in Screen 8 with your own printer graphic replacing my artful bitmap.
You can add icons to smscust.dll in a similar fashion. The resource script entry for a Printer icon looks something like
PDG_PRINTER_PRINTER_DETAILS ICON DISCARDABLE Printdet.ico
As you can see from my custom graphic in Screen 8 (under Name and to the left of HP Printer 1), I'm not much of an artist. Fortunately, VC++ makes it easy to borrow from existing graphics so you don't have to create bitmaps and icons from scratch. Let's start by swiping some graphics from NT's surplus of neat icons and bitmaps.
- Assuming VC++ is running and the SMSCust project is open with Screen 9 (page 149) showing, select File, Open from the VC++ me
- In the Open dialog box, select Executable Files (*.exe,*.dll,*.ocx) in the Files of Type drop-down list box, and choose Resources in the Open As drop-down list box.
- Navigate the Open dialog box to your NT System32 subdirectory (e.g., c:\winnt\system32). On NT 4.0, find the file shell32.dll (if you're running an earlier version of NT, look for progman.exe or main.cpl). Select this file, check the Open as Read-Only box to protect it from accidental change, and click Open.
- In the right pane of VC++, you'll see several folders under the shell32.dll folder. Expand the Icon folder, which you see in Screen 9. (Notice that all the numbers are resource names.)
- Now you can start pilfering resources. I happen to know that the number 17 resource contains several good printer resources, and number 173 reminds me of fonts. Drag these resources onto the SMSCust resources script folder in the left pane. VC++ automatically creates an Icon folder under SMSCust resources and .ico files in the project subdirectory. VC++ generates the filenames from the resource names, so you don't have to worry about them.
- You'll want to rename these resources from their exciting numeric names. Let's change 17 to "PDG_PRINTER_PRINTER_DETAILS" and 173 to "PDG_STD_PRINTER_FONTS". You change these names the same way you previously changed the bitmap name to "PRINTER_PRINTER". Right-click the Icons, and choose Properties from the Context menu. Change the ID: fields to "PDG_PRINTER_PRINTER_DETAILS" and "PDG_STD_PRINTER_FONTS" (remember to include the quotes).
- Close shell32.dll, and save your project files (select File, Save All from the VC++ menu).
- Select Build, Build SMSCust.dll from the VC++ menu to incorporate the new resources into smscust.dll.
- Copy smscust.dll from the Release subdirectory into c:\smsres. Close the SMS Administrator, and restart it. You will still see the Printer bitmap representing HP Printer 1 in the SMS Administrator Sites window.
- Open the properties window for HP Printer 1. You will see the custom graphics, as in Screen 10.
Congratulations! Not only have you created a professional looking result in SMS, you're also a C++ programmer! As I promised, you didn't have to do any coding beyond what you had to enter for smscust.cpp (and we stole that from the SMS software development kit--SDK). If you have VC++, you don't even need that code. You can create a blank file, name it smscust.cpp, and add it to the SMSCust project, and VC++ will automatically generate the DllMain code behind the scenes. Say, what do all these C++ programmers do anyway?
You can try adding icons and bitmaps using the naming conventions I've described in this article. For example, we didn't add anything specific for the Laser Printer role. Try out some of these combinations.
If you put in a little work, you can have some very intuitive graphics for specific types of objects and generic catch-alls as you add new inventory. An interesting DLL to peruse for graphics is the SMS standard resource DLL, smsres.dll. You'll find most of the SMS icons and bitmaps there, including some that have Hermes in their names (Hermes was Microsoft's code name for SMS). You can override these standard SMS graphics. The sample in the SMS SDK makes some of these standard objects look like a human eye--interesting, but kind of eerie!
My next article will explain how you can add personnel data such as employee name, title, and department to the SMS inventory database directly from a human resources database. You can then use this information to associate workstations with a user or department. This ability is useful when you are distributing software based on organizational needs.
LISTING 1: The regscrpt.ini Script File
\Registry\Machine\Software\Microsoft\SMS ResDlls Installed = REG_MULTI_SZ "DLLNum1" "DLLNum2" DLLNum1 PathName = REG_SZ myres.dll DLLNum2 PathName = REG_SZ myicons.dll DLLNum3 PathName = REG_SZ notready.dll