Click here to Skip to main content
Click here to Skip to main content

Custom Wizard for OpenGL in Visual Studio 2010

By , 5 Aug 2010
Rate this:
Please Sign up or sign in to vote.
OpenGL_Custom_Wizard_Project_2.png

OpenGL_Custom_Wizard.png

Introduction

This article explains about custom wizard making and OpenGL custom wizard in Visual Studio 2010 using MFC custom wizard. Many people have a question about custom wizard in Visual Studio 2010. This article explains "How to make Custom Wizard in Visual Studio 2010 using OpenGL?".

Background

Previously in "Custom Wizard for OpenGL in Visual Studio .NET", I explained Visual Studio 2003/2005 Custom Wizard. Visual Studio 2008 was not different between Visual Studio 2003/2005 and Visual Studio 2008. Visual Studio 2010 environment is very similar to Visual Studio 2008. But, Visual Studio 2010 environment is very variable.

Firstly, Project XML file format is different from *.vcproj to *.vcxproj. And secondly, “Project properties” are very variable.

Overview

You have to copy the source code from zip file to Visual Studio 2010 folder. If you installed Visual Studio 2010 to C driver, your Visual Studio 2010 path is C:\Program Files\Microsoft Visual Studio 10.0.

  1. You will find Visual C++ folder in C:\Program Files\Microsoft Visual Studio 10.0\VC.
  2. Copy folders "vcprojects" and "VCwizards" from zip files to VC.

And, you will be ready to create Custom wizard.

Create Custom Wizard

If you know the custom wizard making process, you have to create a custom wizard project in Visual Studio 2010 using “File > New > Project” menu. And, you can select custom wizard project in Visual C++ project list. Finally, you finish button click.

Visual_C___Custom_Wizard.png

Congratulations! You have success with your first custom wizard file.

Visual_Studio_2010.png

Change Your Custom Wizard Files

Custom Wizard file is composed of HTML files, Image files, miscellaneous files, Script files and Template files.

First, HTML files make wizard main frame with HTML tags. Visual Studio 2010 default makes a default.htm file. But, this file is not useful for your OpenGL custom wizard. So, you have to delete default.htm file from Solution Explorer. Next, source files import HTM files from this article zip file.

C:\Program Files\Microsoft Visual Studio 10.0\VC\VCWizards\AppWiz\
	OpenGL\Application\html\1033

html.png

Second, Image files is empty when Visual Studio 2010 Custom Wizard makes default custom wizard. Image files use to make image screen when you edit your custom wizard. OpenGL wizard image files use to help choice understand on Alpha, Fog, Perspective, etc., properties . All files insert to Image files using Visual Studio 2010 Solution Explorer.

C:\Program Files\Microsoft Visual Studio 
	10.0\VC\VCWizards\AppWiz\OpenGL\Application\images

image.png

Third, miscellaneous files is properties for Custom wizard properties. For examples, Style file is wizard style on HTML.

 C:\Program Files\Microsoft Visual Studio 10.0\VC\VCWizards\1033\NewStyle.css

For example on HTM:

<HEAD>
<TITLE>'OpenGL Wizard'</TITLE>
<META NAME="vs_targetSchema" CONTENT="http://schemas.microsoft.com/intellisense/ie5">
<LINK ID="LINKURL" REL="stylesheet" <sub><sup>HREF</sup></sub><sub><sup>="../../../../../1033/NewStyles.css</sup></sub>">
<!--  -->
<!-- The SYMBOL tag is used to set the default values for the user-defined symbols.-->
<!--  -->
<SYMBOL NAME='WIZARD_DIALOG_TITLE' TYPE=text VALUE='OpenGL Wizard'></SYMBOL>
<SYMBOL NAME='SAMPLE_CHECKBOX' TYPE=checkbox VALUE=true></SYMBOL>
<SYMBOL NAME='SAMPLE_RADIO_OPTION1' TYPE=checkbox VALUE=true></SYMBOL>
<SYMBOL NAME='SAMPLE_RADIO_OPTION2' TYPE=checkbox VALUE=false></SYMBOL>
<SYMBOL NAME='SAMPLE_LISTBOX' TYPE=select-one VALUE='option1'></SYMBOL>
<SYMBOL NAME='SOURCE_FILTER' TYPE=text VALUE='txt'></SYMBOL>
<SYMBOL NAME='APP_TYPE_SUMMARY' TYPE=text VALUE='//TODO: Application summary'></SYMBOL>
</HEAD>

*.vsdir extension file is a custom wizard file path when you create a new project in Visual Studio.

C:\Program Files\Microsoft Visual Studio 10.0\VC\vcprojects\OpenGL\OpenGL_Wizard.vsdir

vsdir file contents:

. ..\OpenGL_Wizard.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|
	#2000|100|#2001|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154

*.vsz extension file is a properties file which your custom wizard script defines.

C:\Program Files\Microsoft Visual Studio 10.0\VC\vcprojects\OpenGL_Wizard.vsz

vsz file contents:

VSWIZARD 7.0
Wizard=VsWizard.VsWizardEngine.10.0
Param="WIZARD_NAME = Application"
Param="RELATIVE_PATH = VCWizards\AppWiz\OpenGL"
Param="CONSOLE_TYPE_ONLY = false"
Param="WIZARD_ID = 103"

Template.inf file is a file list for custom wizard. This INF extension file is very important for new project from template file information.

C:\Program Files\Microsoft Visual Studio 10.0\VC\VCWizards\
	AppWiz\OpenGL\Application\templates\1033.Template.inf

Template.inf file contents:

readme.txt
sample.txt
stdafx.h
stdafx.cpp
OpenGLView.h
OpenGLView.cpp
OpenGLDoc.h
OpenGLDoc.cpp
OpenGL.h
OpenGL.cpp
MainFrm.h
MainFrm.cpp
OpenGL.rc
targetver.h
Res/OpenGL.ico
Res/OpenGL.rc2
Res/OpenGLDoc.ico
Res/Toolbar.bmp
Res/OpenGL.manifest
Resource.h
earth.bmp

misellaneous.png

Editing Custom Wizard Script File

C:\Program Files\Microsoft Visual Studio 10.0\VC\VCWizards\AppWiz\OpenGL\Application\scripts\1033\default.js file is very~ very~ very~ important. This file is similar between Visual Studio 2003/2005/2008 and Visual Studio 2010. But, the script file is different project extension, target .NET Framework version, add on configuration properties on Visual Studio 2010. But the other is the same within Visual Studio 2003/2005/2008.

function OnFinish(selProj, selObj)
{
 try
 {
  var strProjectPath = wizard.FindSymbol('PROJECT_PATH');
  var strProjectName = wizard.FindSymbol('PROJECT_NAME');

  selProj = CreateCustomProject(strProjectName, strProjectPath);
  AddConfig(selProj, strProjectName);
  AddFilters(selProj);

  var InfFile = CreateCustomInfFile();
  AddFilesToCustomProj(selProj, strProjectName, strProjectPath, InfFile);
  PchSettings(selProj);
  InfFile.Delete();

  selProj.Object.Save();
 }
 catch(e)
 {
  if (e.description.length != 0)
   SetErrorInfo(e);
  return e.number
 }
}

function CreateCustomProject(strProjectName, strProjectPath)
{
 try
 {
  var strProjTemplatePath = wizard.FindSymbol('PROJECT_TEMPLATE_PATH');
  var strProjTemplate = '';
  strProjTemplate = strProjTemplatePath + '\\default.vcxproj';

  var Solution = dte.Solution;
  var strSolutionName = "";
  if (wizard.FindSymbol("CLOSE_SOLUTION"))
  {
   Solution.Close();
   strSolutionName = wizard.FindSymbol("VS_SOLUTION_NAME");
   if (strSolutionName.length)
   {
    var strSolutionPath = strProjectPath.substr
	(0, strProjectPath.length - strProjectName.length);
    Solution.Create(strSolutionPath, strSolutionName);
   }
  }

  var strProjectNameWithExt = '';
  strProjectNameWithExt = strProjectName + '.vcxproj';

  var oTarget = wizard.FindSymbol("TARGET");
  var prj;
  if (wizard.FindSymbol("WIZARD_TYPE") == vsWizardAddSubProject)  // vsWizardAddSubProject
  {
   var prjItem = oTarget.AddFromTemplate(strProjTemplate, strProjectNameWithExt);
   prj = prjItem.SubProject;
  }
  else
  {
   prj = oTarget.AddFromTemplate(strProjTemplate, strProjectPath, strProjectNameWithExt);
  }
  var fxtarget = wizard.FindSymbol("TARGET_FRAMEWORK_VERSION");
  if (fxtarget != null && fxtarget != "")
  {
      fxtarget = fxtarget.split('.', 2);
      if (fxtarget.length == 2)
   prj.Object.TargetFrameworkVersion = parseInt(fxtarget[0]) * 
				0x10000 + parseInt(fxtarget[1])
  }
  return prj;
 }
 catch(e)
 {
  throw e;
 }
}

function AddFilters(proj)
{
 try
 {
     // Add the folders to your project
     var group;
        
     group = proj.Object.AddFilter('Source Files');
        group.Filter = 'cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx';

     group = proj.Object.AddFilter('Header Files');
     group.Filter = 'h;hpp;hxx;hm;inl;inc;xsd';

     group = proj.Object.AddFilter('Resource Files');
     group.Filter = 'rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;
			jpe;resx;tiff;tif;png;wav';
 }
 catch(e)
 {
  throw e;
 }
}

function AddConfig(proj, strProjectName)
{
 try
 {
  var config = proj.Object.Configurations('Debug');
  config.CharacterSet = charSetMBCS;
  config.useOfMfc = useOfMfc.useMfcDynamic;

  var CLTool = config.Tools('VCCLCompilerTool');
  // TODO: Add compiler settings

  CLTool.DebugInformationFormat = debugEnabled; 
  CLTool.DebugInformationFormat = debugOption.debugEditAndContinue;
  CLTool.SuppressStartupBanner = true; 
  CLTool.RuntimeLibrary = runtimeLibraryOption.rtMultiThreadedDebugDLL; 
  CLTool.WarningLevel = warningLevelOption.warningLevel_3; 
  CLTool.Optimization = optimizeOption.optimizeDisabled;
  CLTool.MinimalRebuild = true;
  CLTool.DebugInformationFormat = debugOption.debugEditAndContinue;
  CLTool.PreprocessorDefinitions = "WIN32;_WINDOWS;_DEBUG";
  CLTool.UsePrecompiledHeader = pchOption.pchGenerateAuto; 

  var LinkTool = config.Tools('VCLinkerTool');
  // TODO: Add linker settings

  LinkTool.ProgramDatabaseFile = "$(OutDir)/$(ProjectName).pdb"; 
  LinkTool.GenerateDebugInformation = true;
  LinkTool.LinkIncremental = linkIncrementalYes; 
  LinkTool.OutputFile = "$(OutDir)/$(ProjectName).exe";
  LinkTool.SuppressStartupBanner=true;  // nologo
  LinkTool.AdditionalDependencies="opengl32.lib glu32.lib glut32.lib";
  LinkTool.SubSystem = subSystemOption.subSystemWindows;

  var MIDLTool = config.Tools('VCMIDLTool');
  MIDLTool.PreprocessorDefinitions = '_DEBUG';
  MIDLTool.MkTypLibCompatible = 'false';
  MIDLTool.ValidateParameters = 'false';

  var ResourceTool = config.Tools('VCResourceCompilerTool');  
  // TODO: Add Resource Compiler settings  
  ResourceTool.Culture = enumResourceLangID.rcEnglishUS;  
  ResourceTool.PreprocessorDefinitions = "_DEBUG";  
  ResourceTool.ResourceOutputFileName = "$(IntDir)/$(InputName).res"  

  config = proj.Object.Configurations('Release');
  config.CharacterSet = charSetMBCS; 
  config.useOfMfc = useOfMfc.useMfcDynamic;
  
  var CLTool = config.Tools('VCCLCompilerTool');
  // TODO: Add compiler settings

  CLTool.DebugInformationFormat = debugEnabled; 
  CLTool.DebugInformationFormat = debugOption.debugEnabled; 
  CLTool.SuppressStartupBanner = true; 
  CLTool.RuntimeLibrary = runtimeLibraryOption.rtMultiThreadedDLL; 
  CLTool.WarningLevel = warningLevelOption.warningLevel_3; 
  CLTool.Optimization = optimizeOption.optimizeMaximizeSpeed;
  CLTool.MinimalRebuild = true;
  CLTool.PreprocessorDefinitions = "WIN32;_WINDOWS;NDEBUG";
  CLTool.UsePrecompiledHeader = pchOption.pchGenerateAuto; 

  var LinkTool = config.Tools('VCLinkerTool');
  // TODO: Add linker settings

  LinkTool.ProgramDatabaseFile = "$(OutDir)/$(ProjectName).pdb"; 
  LinkTool.GenerateDebugInformation = true;
  LinkTool.LinkIncremental = linkIncrementalYes; 
  LinkTool.OutputFile = "$(OutDir)/$(ProjectName).exe";
  LinkTool.SuppressStartupBanner=true;  // nologo
  LinkTool.AdditionalDependencies="opengl32.lib glu32.lib glut32.lib";
  LinkTool.SubSystem = subSystemOption.subSystemWindows; 
  
  var MIDLTool = config.Tools('VCMIDLTool');
  MIDLTool.PreprocessorDefinitions = 'NDEBUG';
  MIDLTool.MkTypLibCompatible = 'false';
  MIDLTool.ValidateParameters = 'false';
  
  var ResourceTool = config.Tools('VCResourceCompilerTool');
  // TODO: Add Resource Compiler settings
  ResourceTool.Culture = enumResourceLangID.rcEnglishUS;
  ResourceTool.PreprocessorDefinitions = "";
  ResourceTool.ResourceOutputFileName = "$(IntDir)/$(InputName).res"
 }
 catch(e)
 {
  throw e;
 }
}

function PchSettings(proj)
{
 // TODO: specify pch settings
}

function DelFile(fso, strWizTempFile)
{
 try
 {
  if (fso.FileExists(strWizTempFile))
  {
   var tmpFile = fso.GetFile(strWizTempFile);
   tmpFile.Delete();
  }
 }
 catch(e)
 {
  throw e;
 }
}

function CreateCustomInfFile()
{
 try
 {
  var fso, TemplatesFolder, TemplateFiles, strTemplate;
  fso = new ActiveXObject('Scripting.FileSystemObject');

  var TemporaryFolder = 2;
  var tfolder = fso.GetSpecialFolder(TemporaryFolder);
  var strTempFolder = tfolder.Drive + '\\' + tfolder.Name;

  var strWizTempFile = strTempFolder + "\\" + fso.GetTempName();

  var strTemplatePath = wizard.FindSymbol('TEMPLATES_PATH');
  var strInfFile = strTemplatePath + '\\Templates.inf';
  wizard.RenderTemplate(strInfFile, strWizTempFile);

  var WizTempFile = fso.GetFile(strWizTempFile);
  return WizTempFile;
 }
 catch(e)
 {
  throw e;
 }
}

function GetTargetName(strName, strProjectName)
{
 try
 {
  // TODO: set the name of the rendered file based on the template filename
  var strTarget = strName;
  var strProjectName = wizard.FindSymbol('PROJECT_NAME');

  if (strName == 'readme.txt')
   strTarget = 'ReadMe.txt';

  if (strName == 'sample.txt')
   strTarget = 'Sample.txt';
   
  if (strName == 'stdafx.cpp')
   strTarget =  'stdafx.cpp';
 
  if (strName == 'stdafx.h')
   strTarget =  'stdafx.h'; 

  if (strName == 'OpenGL.h')
   strTarget =  strProjectName + '.h';  
   
  if (strName == 'OpenGL.cpp')
   strTarget =  strProjectName + '.cpp';  

  if (strName == 'MainFrm.h')
   strTarget =  'MainFrm.h';  
   
  if (strName == 'MainFrm.cpp')
   strTarget =  'MainFrm.cpp';    

  if (strName == 'OpenGLView.h')
   strTarget =  strProjectName + 'View.h';  
   
  if (strName == 'OpenGLView.cpp')
   strTarget =  strProjectName + 'View.cpp';   

  if (strName == 'OpenGLDoc.h')
   strTarget =  strProjectName + 'Doc.h';  
   
  if (strName == 'OpenGLDoc.cpp')
   strTarget =  strProjectName + 'Doc.cpp';   

  if (strName == 'OpenGL.rc')
   strTarget =  strProjectName + '.rc';

  if (strName == 'resource.h')
   strTarget =  'Resource.h';  
   
  if (strName == 'Res/OpenGL.ico')
   strTarget =  'Res/' + strProjectName + '.ico';     

  if (strName == 'earth.bmp')
   strTarget =  'earth.bmp';     

  if (strName == 'Res/OpenGL.rc2')
   strTarget =  'Res/' + strProjectName + '.rc2';
   
  if (strName == 'Res/OpenGLDoc.ico')
   strTarget =  'Res/' + strProjectName + 'Doc.ico';     
      
  if (strName == 'Res/OpenGL.manifest')
   strTarget =  'Res/' + strProjectName + '.manifest';       
  
  return strTarget; 
 }
 catch(e)
 {
  throw e;
 }
}

function AddFilesToCustomProj(proj, strProjectName, strProjectPath, InfFile)
{
 try
 {
  var projItems = proj.ProjectItems

  var strTemplatePath = wizard.FindSymbol('TEMPLATES_PATH');

  var strTpl = '';
  var strName = '';

  var strTextStream = InfFile.OpenAsTextStream(1, -2);
  while (!strTextStream.AtEndOfStream)
  {
   strTpl = strTextStream.ReadLine();
   if (strTpl != '')
   {
    strName = strTpl;
    var strTarget = GetTargetName(strName, strProjectName);
    var strTemplate = strTemplatePath + '\\' + strTpl;
    var strFile = strProjectPath + '\\' + strTarget;

    var bCopyOnly = false;  //"true" will only copy the file 
	// from strTemplate to strTarget without rendering/adding to the project
    var strExt = strName.substr(strName.lastIndexOf("."));
    if(strExt==".bmp" || strExt==".ico" || strExt==".gif" || 
			strExt==".rtf" || strExt==".css")
     bCopyOnly = true;
    wizard.RenderTemplate(strTemplate, strFile, bCopyOnly);
    proj.Object.AddFile(strFile);
   }
  }
  strTextStream.Close();
 }
 catch(e)
 {
  throw e;
 }
}

Visual Studio Wizard Insert

Last, if you make custom wizard project, you have to build this project. But, if you don't make custom wizard, you should insert custom wizard to Visual Studio 2010 Wizard list. C:\Program Files\Microsoft Visual Studio 10.0\VC\vcprojects\vc.svdir file is a list of Visual Studio 2010. You have to change your custom wizard install path for OpenGL Custom wizard file.

ATL|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1041|10
vcNET|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1040|20
General|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1044|30
MFC|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1042|40
SmartDevice|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1045|50
Win32|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1043|60
Win32Console.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1204|10|
	#1205|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MFCAppWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1161|20|
	#1162|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
Win32Wiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1171|30|
	#1172|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
EmptyProj.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1279|40|
	#1280|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
ATLWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1155|50|#1156|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MFCDLLWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1163|60|#1164|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MC++WinApp.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1221|70|#1222|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|FormApp
MC++AppWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1173|80|#1174|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MC++EmptyProj.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1177|90|#1178|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MakefileAppWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1183|100|#1184|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MFCCtlWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1165|100|#1166|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MC++ClassLib.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1175|100|#1176|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
MC++WinCtrlLib.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1243|100|#1244|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
SDWin32Wiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1404|100|#1405|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
SDATLWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1400|100|#1401|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
SDMFCAppWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1402|100|#1403|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
SDMFCCtlWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1406|100|#1407|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
SDMFCDLLWiz.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1408|100|#1409|
	{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154
OpenGL_Wizard.vsz|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#2000|100|
	#2001|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|0|4096|#1154

Point of Interest and History

If you want a detailed description, you have to see my previous article on "Custom Wizard for OpenGL in Visual Studio .NET".

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Youngho Kim
Software Developer
Korea (Republic Of) Korea (Republic Of)
I hope to help your coding processing.

Comments and Discussions

 
Questionquestion Pinmemberrafael241712-Oct-13 15:20 
Questionscript error Pinmemberrewex23-Oct-11 11:42 
AnswerRe: script error PinmemberHartmut Gottenstraeter4-Feb-12 3:10 
GeneralScript Error PinmemberSharjith8-Aug-10 12:05 
GeneralRe: Script Error PinmemberYoungho Kim8-Aug-10 15:43 
GeneralRe: Script Error PinmemberPieter2128-Sep-11 8:17 
GeneralRe: Script Error Pinmemberddp51623-Nov-11 17:44 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140415.2 | Last Updated 5 Aug 2010
Article Copyright 2010 by Youngho Kim
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid