Click here to Skip to main content
15,881,172 members
Articles / Programming Languages / C#

C# SDI/MDI Application Wizards

Rate me:
Please Sign up or sign in to vote.
3.50/5 (28 votes)
30 Nov 20038 min read 226.4K   2.7K   60   45
Useful project templates for C# document-centric applications
In this article, I'll show what is brought in the zip files, how to install the application wizard, the meaning of SDI/MDI and how it was built

Image 1

Two new C# project templates

Introduction

It's a fact of life that C# project templates provided by the VS.NET IDE lack SDI/MDI support. Since SDI/MDI fit many real-world requirements when writing applications, especially those being document-centric, I thought that would be nice and hopefully useful to share this stuff.

In the remainder of this article, I'll show:

  • what is brought in the zip files
  • how to install the application wizard
  • the meaning of SDI/MDI, huh ?
  • how it was built

1. Installing the Wizard

The zip files have everything you need to get the wizards installed on either VC#2002 or VC#2003. The package can be broken down as follows:

  • SDIMDIwizardinstaller.exe, command-line installer
  • CSharpSDIWiz folder, templates files for the SDI wizard
  • CSharpMDIWiz folder, templates files for the MDI wizard
  • *.vsz files, parent files for the wizard, IDE version specific

If you only want to install the stuff and are not very interested in the details, then extract all the stuff in some folder, and then double-click on SDIMDIwizardinstaller.exe if you are using VC#2003. If you are using VC#2002, bring a command-line up, and type SDIMDIwizardinstaller.exe 2002. Once the wizards are installed, you can delete the temporary extraction folder.

The installer does the following job:

  1. Check-out the command-line, whether 2002 is being passed
  2. According to the command-line, retrieve the install directory of VC# from the registry
  3. Recurse-copy all template files in the <installdir> / VC#Wizards subfolder
  4. Copy all *.vsz files in the <installdir> / CSharpProjects subfolder
  5. Update the <installdir> / CSharpProjects / CSharp.vsdir file and add two entries if they don't exist yet.

The code for the installer is reproduced below:

C#
static void Main(string[] args)
{
 // installation sequence
 // 1- get VC# install dir (regkey)
 // 2- copy template files in the VC# subfolder for files
 // 3- copy vsz files in the VC# subfolder for project wizards
 // 4- add two entries in the VC# vsdir file so that the IDE sees them

 // check out cmdline (type 2002 for VC#2002, none or 
 // everything else for VC#2003)
 bool bIsFor2002 = args.GetLength(0)>0 && args[0] == "2002";

 // 1- regkey
 RegistryKey k;
 if (bIsFor2002)
  k = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
    @"Software\Microsoft\VisualStudio\7.0", true);
 else
  k = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(
    @"Software\Microsoft\VisualStudio\7.1", true);

 String szWizardDir = (String) k.GetValue("InstallDir") + @"..\..\VC#\";

 if ( !Directory.Exists(szWizardDir) )
 {
  System.Console.WriteLine("Make sure to install VC# first");
  return;
 }

 // 2- template files
 String szSrcDir = AppDomain.CurrentDomain.BaseDirectory;
 RecurseCopyFiles(szSrcDir + @"\CSharpSDIWiz", szWizardDir + 
    @"VC#Wizards\CSharpSDIWiz");
 RecurseCopyFiles(szSrcDir + @"\CSharpMDIWiz", szWizardDir +
    @"VC#Wizards\CSharpMDIWiz");

 // 3- vsz files
 if (bIsFor2002) // VC# 2002
 {
  File.Copy(szSrcDir + @"\CSharpSDI_VS2002.vsz", szWizardDir + 
    @"CSharpProjects\CSharpSDI.vsz",true);
  File.Copy(szSrcDir + @"\CSharpMDI_VS2002.vsz", szWizardDir + 
    @"CSharpProjects\CSharpMDI.vsz",true);
 }
 else // VC# 2003
 {
  File.Copy(szSrcDir + @"\CSharpSDI_VS2003.vsz", szWizardDir + 
    @"CSharpProjects\CSharpSDI.vsz",true);
  File.Copy(szSrcDir + @"\CSharpMDI_VS2003.vsz", szWizardDir + 
    @"CSharpProjects\CSharpMDI.vsz",true);
 }

 // 4- update vsdir file (append 2 entries if they don't exist yet)
 bool bAlreadyInstalled = false;
 using (StreamReader sr = new StreamReader( szWizardDir + 
    @"CSharpProjects\CSharp.vsdir" )) 
 {
  String line;
  while ((line = sr.ReadLine()) != null) 
  {
   if (line.IndexOf("CSharpSDI.vsz") > -1)
   {
    bAlreadyInstalled = true;
    break;
   }
  }
  sr.Close();

  if (!bAlreadyInstalled)
  {
   using (StreamWriter sw = File.AppendText( szWizardDir + 
    @"CSharpProjects\CSharp.vsdir" )) 
   {
    sw.WriteLine("CSharpSDI.vsz|{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}" + 
       "|SDI Application|11|" +
       "Builds a Windows single document interface (SDI) application|" +
       "{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}|4554| |SDIApplication");
    sw.WriteLine("CSharpMDI.vsz|{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}" +
       "|MDI Application|12|" +
       "Builds a Windows single document interface (MDI) application|" +
       "{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}|4554| |MDIApplication");
   }
  }
 }
}

static void RecurseCopyFiles(String szSrcDir, String szDestDir)
{
 if ( !Directory.Exists(szDestDir) )
  Directory.CreateDirectory(szDestDir);

 string [] fileEntries = Directory.GetFiles(szSrcDir);
 foreach(string fileName in fileEntries)
  File.Copy(fileName, szDestDir + fileName.Substring(
    fileName.LastIndexOf('\\')),true);

 // recurse
 string [] subdirectoryEntries = Directory.GetDirectories(szSrcDir + @"\");
 foreach(string subdirectory in subdirectoryEntries)
 {
  String szSrcNextDir = subdirectory;
  String szDestNextDir = szDestDir + subdirectory.Substring(
     subdirectory.LastIndexOf('\\'));
  RecurseCopyFiles(szSrcNextDir, szDestNextDir);
 }
}

The MDI application is derived from a sample provided by MS in the VS.NET CDs, called "Scribble".

2. What is SDI/MDI?

SDI/MDI is short for Simple Document Interface / Multiple Document Interface.

Those words are used by VC++ MFC programmers to refer to application wizards that are built within the VC++ IDE and which provide rich and useful application skeleton code. We could also speak about MVC (Model View Controller). In fact, the document-view paradigm is a way to provide functionalities to an application such as the ability to create a new document of a given type (file extension), open an existing document, and save a working document. Each document is rendered, whether on screen or not, using one or more views. The document orders the views to update themselves based on events or other application logic. Each view implements an OnPaint method to display the content purposely. For instance, if a document stores the bits for a 3D graphic model, then one view could be used to display a front view of it, while another view could be used to display a left view of it. And so on.

An SDI application is a one document - one view application. Depending on requirements, one can add views to it. Notepad is an SDI application.

An MDI application is a multiple document - multiple view application. Microsoft Word is an MDI application.

Image 2

Sample MDI application

3. Views and Documents

Both SDI and MDI wizards share a common "architecture". The main form acts like a container. One or more documents (instances of the SDIDoc class) hold all the documents life-cycle (open, save, print, is it dirty?, ...) as well as the application logic itself. One or more views for each document (instances of the SDIView class) hold what's draw on screen or being sent to the printer or any other device.

In the MDI wizard, the main form not only acts like a container, it is really a container and uses the Winforms MDI properties associated to each class derived from System.Windows.Forms.Form, namely IsMdiChild (false for the container), IsMdiContainer (true for the container), MdiChildren (collection of Form-derived classes) and MdiParent (null for the container).

In the SDI wizard, the main form is a container but is mostly a simple form by itself.

In both the SDI and MDI wizards, the drawing and printing are delegated to views. Each view knows its "parent" document, and can use the properties from that document to draw itself, etc.

By analogy, the serialization (load / save) is delegated to the document. Like in the MFC wizard, a document is being associated a file extension, .doc by default. Each document knows all the views being attached, and this custom mechanism is used to delegate the calls.

4. Inside the Application Wizard

Installing the application wizard allows to create projects using either of two new project templates. Once installed, the two new project templates appear with a clearly identifiable icon and label from the VS.NET project wizard. Both can be used as if you were using the default Windows Application project template. Below are explanations on how to install the application.

Below are the steps to add both SDI and MDI application wizards to the list of known C# project wizards.

CSharpSDIWiz.vsz // VC# 2002

VSWIZARD 7.0
Wizard=VsWizard.VsWizardEngine
Param="WIZARD_NAME = CSharpSDIWiz"
Param="WIZARD_UI = FALSE"
Param="PROJECT_TYPE = CSPROJ"

CSharpMDIWiz.vsz // VC# 2002

VSWIZARD 7.0
Wizard=VsWizard.VsWizardEngine
Param="WIZARD_NAME = CSharpMDIWiz"
Param="WIZARD_UI = FALSE"
Param="PROJECT_TYPE = CSPROJ"

CSharpSDIWiz and CSharpMDIWiz are meant to be <VC#dir> \ VC#Wizards subfolders. Let's create them. Each of these folders must follow the project template guideline, i.e., have a predefined structure. The structure for a simple project template is straight forward: there must be two subfolders, namely Scripts and Templates. In each of these two subfolders must be a localized folder whose name depends on the language version of your VS.NET installation. We assume in the remainder of this article that it's 1033 (US english).

  1. Find the VC# installation folder. On my machine, it's c:\program files\VC#, and it has subfolders like VC#Wizards and CSharpProjects. Let's call it <VC#dir> for the remainder of the article.
  2. When you bring up the VS.NET project box, VS.NET lists all existing .vsdir files, including those found in particular <VC#dir> subfolders. Each .vsdir file is a category of project templates. The <VC#dir> \ CSharpProjects \ CSharp.vsdir lists all standard C# project templates. The definition of the .vsdir file format is detailed here[^]. Entries in a .vsdir file are referenced .vsz files which in turn are small project template identifiers. Among those identifiers is CSharpEXE.vsz, the project which helps build simple C# Windows Applications. What we are going to do is add two entries to the CSharp.vsdir file, one for the SDI project template, one for the MDI project template. So, edit the CSharp.vsdir and clone twice the line referencing CSharpExe.vsz, so as to make sure our two projects are built from this starting point. The documentation for the .vsz file can be found here[^].

    Those two files must be edited, and the reference to the CSharpEXEWiz folder must be replaced with corresponding references to CSharpSDIWiz and CSharpMDIWiz. Those are references to subfolders we are going to create in a while. The two .vsz files should look like this:

  3. Filling the Scripts \ 1033 folder: This folder is supposed to contain a default.js script file. The implementation in default.js is what differentiates this project template from another and brings JavaScript application code aimed to build the actual .csproj file based on the core JavaScript source code from <VC#dir> \ VC#Wizards \ 1033 \ Common.js and the actual VS.NET IDE extensibility object model[^]. The default.js file assumes that Form1.cs is the application mainform. So to make things easier, both SDI and MDI projects are such that Form1.cs is the mainform. Otherwise, default.js would have to be manually edited. Just copy the default.js file found in the CSharpEXEWiz \ Scripts \ 1033 folder.

  4. Filling the Templates \ 1033 folder: This folder is supposed to contain a Templates.inf file, and all files that are to be included in the target .csproj project file. Things get easy since the Templates.inf file simply lists all files in this folder, one per line.

In short, here is how the file hierarchy should look like for each WIZ subfolder:

CSharpSDIWiz
 + Scripts
   + 1033
     + default.js  (a copy from the one existing in the CSharpEXEWiz folder)
 + Templates
   + 1033
      + Templates.inf
      + Form1.cs
      + Form1.resx
      + SDIDoc.cs
      + SDIView.cs
      + SDIView.resx
      + New.bmp
      + Open.bmp
      + Preview.bmp
      + Print.bmp
      + Save.bmp
      + App.ico

Where Templates.inf contains this:

Form1.cs
Form1.resx
SDIDoc.cs
SDIView.cs
SDIView.resx
New.bmp
Open.bmp
Preview.bmp
Print.bmp
Save.bmp
App.ico

Last note, to make sure namespaces are properly transferred to the target project, we have to change the content of the Form1.cs file from the original stand-alone project:

C#
namespace SDIApp
{
   ...

with this (in the Templates \ 1033 folder):

C#
namespace [!output SAFE_NAMESPACE_NAME]
{
   ...

What is just done and finished for CSharpSDIWiz must be also done for CSharpMDIWiz.

5. Unifying Both Project Templates?

I have to confess that, for trivial reasons, I have brought two wizards up instead of only one. Actually, there is no need to have two additional icons in the project box, one for SDI and one for MDI. The idea is that, in the .vsz file, it's possible to let the Wizard engine know about a HTML UI which, in turn, would let the user choose SDI or MDI, get the return value, and act accordingly. Although this is certainly doable, this is not what I have done for this release.

For those interested in HTML UI-based wizards, just check out the undocumented wizard named CSharpIndexerWiz.

History

  • 3rd May, 2003: Initial publication
  • 30th November, 2003: Article updated
    • added a user-friendly installer
    • the SDI wizard really creates an SDI app

License

This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.

A list of licenses authors might use can be found here.


Written By
France France
Addicted to reverse engineering. At work, I am developing business intelligence software in a team of smart people (independent software vendor).

Need a fast Excel generation component? Try xlsgen.

Comments and Discussions

 
QuestionPackage not contains files mentioned Pin
Hafiz Sikander Rafiq21-Jan-15 20:12
Hafiz Sikander Rafiq21-Jan-15 20:12 
AnswerRe: Package not contains files mentioned Pin
Hafiz Sikander Rafiq21-Jan-15 20:15
Hafiz Sikander Rafiq21-Jan-15 20:15 
GeneralWhy I Voted "1" Pin
#realJSOP1-Nov-07 3:53
mve#realJSOP1-Nov-07 3:53 
GeneralRe: Why I Voted "1" Pin
Jeffrey Walton28-Nov-07 13:17
Jeffrey Walton28-Nov-07 13:17 
GeneralRe: Why I Voted "1" (My Bad) Pin
Jeffrey Walton28-Nov-07 13:19
Jeffrey Walton28-Nov-07 13:19 
GeneralCorrection. Pin
Prakash Nadar3-Nov-06 22:37
Prakash Nadar3-Nov-06 22:37 
Generalerror with c# 2005 professional : File name or class name not found during Automation operation Pin
vineet1378014-Sep-06 20:05
vineet1378014-Sep-06 20:05 
GeneralError for VC# 2005 Pin
qmlee173310-Aug-06 8:24
qmlee173310-Aug-06 8:24 
QuestionError Message Pin
olddog7725-Apr-06 2:28
olddog7725-Apr-06 2:28 
GeneralHELP!!! Pin
mattp1214846-Dec-04 12:56
mattp1214846-Dec-04 12:56 
GeneralVC# 2005 update [modified] Pin
Stephane Rodriguez.13-Nov-04 22:56
Stephane Rodriguez.13-Nov-04 22:56 
GeneralRe: VC# 2005 update Pin
WilsonProgramming28-Nov-04 2:28
WilsonProgramming28-Nov-04 2:28 
GeneralRe: VC# 2005 update Pin
Stephane Rodriguez.28-Nov-04 7:18
Stephane Rodriguez.28-Nov-04 7:18 
GeneralRe: VC# 2005 update Pin
Stephane Rodriguez.4-Dec-04 8:15
Stephane Rodriguez.4-Dec-04 8:15 
GeneralRe: VC# 2005 update. Please Help!!! Pin
Cyrus the Virus31-Mar-06 4:52
Cyrus the Virus31-Mar-06 4:52 
GeneralSimilar Task Pin
mmcguirk18-Aug-04 3:38
mmcguirk18-Aug-04 3:38 
GeneralRe: Similar Task Pin
S R8-Aug-04 4:52
sussS R8-Aug-04 4:52 
Generalexcellent work Pin
Allen Anderson15-Dec-03 6:41
Allen Anderson15-Dec-03 6:41 
GeneralThis is Great stuff Pin
dotnetsql2-Dec-03 6:56
dotnetsql2-Dec-03 6:56 
GeneralRe: This is Great stuff Pin
Stephane Rodriguez.2-Dec-03 7:02
Stephane Rodriguez.2-Dec-03 7:02 
GeneralRe: This is Great stuff Pin
dotnetsql2-Dec-03 22:26
dotnetsql2-Dec-03 22:26 
GeneralRe: This is Great stuff Pin
Stephane Rodriguez.2-Dec-03 22:59
Stephane Rodriguez.2-Dec-03 22:59 
QuestionInstallation for SharpDevelop IDE? Pin
Chris Meech1-Dec-03 7:08
Chris Meech1-Dec-03 7:08 
AnswerRe: Installation for SharpDevelop IDE? Pin
Stephane Rodriguez.1-Dec-03 9:19
Stephane Rodriguez.1-Dec-03 9:19 
QuestionSimplified Setup? Pin
Chris Sells26-Nov-03 6:19
Chris Sells26-Nov-03 6:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.