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

Extending Office 2007 with Tangram Extension Tools for Application

, 24 Dec 2007 Ms-PL
Rate this:
Please Sign up or sign in to vote.
A new method for Extending Microsoft Office 2007 User Interface using MFC/ATL and .NET technologies.

Introduction

Hi, Merry Christmas! This paper is a gift to developers on Codeproject, it comes from Tangram Team at Beijing, China. In this paper, we will discuss a new method for Extending Microsoft Office 2007 User Interface using MFC/ATL and .NET technologies.

1. Extending Microsoft Office 2007 User Interface

Microsoft has provided the latest version Visual Studio Tools for Office with Visual Studio 2008, by using VSTO, one can extending office UI with Task Panes and Ribbon Components. But can we deep into the inside of Microsoft Office UI Framework? Can we supply some new UI elements which can coexist with existed Office UI elements other than Ribbons or Task Panes?

2. Some Snapshots

By using the method introduced in this paper, developers can extend Office UI as follows:

Extended Office UI

(Other than Ribbons and Task Panes, we can extend MS Word UI with a new UI frame Inside MS Word, you can see that the word document region looks as a “view” of embedded UI frame)

When user active another page in the extended Word UI above, we have a new UI scenario:

(MS Word become a new work space of some Software System)

At runtime, other Extended UI Frame can be loaded at the work region of MS Word, as if MS Word becomes a web browser which navigates a new html page:

(New UI frame Loaded by Tangram Extension Tools for Application at Runtime inside MS Word)

3. Tangram Extension Tools for Application

When you download and decompress the file “Tangram_Extension_Tool.zip”, you get a subdirectory “Tangram_Extension_Tool\Tangram”, you must copy the subdirectory “Tangram” to your system’s “Program Files” Directory in order for Tangram Extension Tools for Application work correctly. In “Tangram\bin” directory, there exists a BAT file “Tangram.bat” which will help you to register the library “TangramDeskManager.dll”, this subdirectory also include “TangramDeskManager.dll” and “TangramCommonExtender.dll”. The Source Code of Tangram Extension Tools for Application is at subdirectory “Tangram\src”.

Tangram Extension Tools for Application is a subset of Tangram infrastructure, it consists of two Visual C++ Projects, the first one is TangramDeskManager which was developed based on MFC/ATL class libraries using Visual Studio 2008, in order to compile this project correctly you should download the source code of ATLServer Library at http://www.codeplex.com/AtlServer, the second one is TangramCommonExtender which was developed based on ATL/CLI using VS2008.

If you are a .NET developer, you must first register the TangramDeskManager.dll, and then add a reference to the TangramCommonExtender library in your .NET Project. If you are a MFC/ATL developer and want to go deep into its inside, we recommend that you should dive into the project TangramDeskManager.

4. Some Backgrounds of Tangram Extension Tools for Application

From a customary perspective, a well-designed Desktop Software always consists of one or more mainframe window and each mainframe window has its own client area window for clients’ operations, as an example, the following is the Mainframe Window of MS Word 2007:

<formulas></formulas>

(MS Word Mainframe Window: the area framed with a red rectangle frame is the client area window)

According to the modern ways to develop desktop software, the user area is monopolized by the mainframe’s client area window, in which the presented features represent the main features for this software. Except some menus, toolbars of the mainframe window, there may be some control bars around the client area window. When a user gets such a software system, it seems that he gets a House, but the basic frame of “this house” is unchangeable and in which the Habitation room is permanently monopolized by the client area contents. However, if this software is well-designed with enough flexibility, the developer or user can add some accessorial extension devices docking to the edges of mainframe window around the client area of this “house” for extending the features of this software system.

For well-designed software, it is completely reasonable for users to expect more from this software, i.e. to mine more benefits and values from it. Since we compare a software system to a house, we naturally expect that, besides the inherit functions of a “house”, the software modules provide by ourselves can also be hosted into this “house”, and after hosted, they can occupy the “habitation room” together with the original occupants within it and can cooperate well with each other(the original occupants can even be hided if necessary), once a software system has these expected features, it will meet more needs of users in more extensive applications. The base point of this idea is to dethroning the monopolization status of the original client area window in the user area with some magic technologies in order to release new room for the new software function modules, if we can implement this base point, then it mean that we can moving the original client area window out of the user area, re-building a new frame within the mainframe window’s user area, and then moving the original client area window back. However, after this process, the thing may be changed, the original client area window loses its monopolization status and new vacant rooms appear. The result of this process is that new room is leaved for other function modules. Let’s take MS Word as an example, we wish to:

1. Move the client area window of MS Word out;

2. Re-constructing a frame within the mainframe window’s user area of MS Word;

Screenshot - image007.jpg

3. Move the client area window of MS Word back;

Screenshot - image008.jpg

4. Allow some new user elements hosted into the new frame;

After new elements are hosted, we can see that one room of the new frame is occupied by the original client area window, the status of original client area window now is equivalent to that of new hosted elements. We expect that new members hosted in this way can enjoy all kinds of “services” provided by the infrastructure of MS Word.

An important question emerges from above discussion: Can we re-construct the User Area of MS Word? A more general question is that: Can we re-construct the client area of meaningful target software? Let’s use Microsoft Word as our target software (For a more reasonable assumption, you can select other meaningful software as target software, instead of Microsoft Word discussed here), if we can implement the above scenario, its means that we can host more and more software features into the target software system(which don’t belong to it previously). Many explications would be derived from the idea discussed as above, once a target software system includes a robust application development model, it means that a meaningful external object model can be hosted into the target software system naturally and can interact with Original Application Object Model each other, for software such as MS Office, this means that we would put it on a position just like software development platform, which is meaningful for the development of really application systems.

A key question which Tangram Extension Tools for Application is dedicated to solve is how to re-construct the Client Areas of these software systems. We expect that Tangram Extension Tools for Application can properly and well support the software systems that support COM/.NET extensions. As you know, an application software model is never completely, for this reason, many software developers always add some extensible interfaces model into their software system in order to satisfy the increasing new needs of users. Tangram Extension Tools for Application is such a software framework which is designed to allow a developer host his (her) flexible and robust extension software model into the target software system (such as Microsoft Office, Internet Explorer, Visual Studio, etc.) naturally, and then enable developer extend the target software system UI naturally and seamlessly, and therefore, allow well interpretation between extended software model and the object model of the target software system.

Let’s take Microsoft Office as an example. As a matter of fact, there are many mature and robust software technologies in the Microsoft Office system. With many really enterprise developments, a lot of software functions are perfectly implemented in the Office system. It is a good idea to develop an application system based on the Office system satisfying application specific needs, but the room that the Office system provides us is still limited, for software system such as ERP, there are a lot of UI elements can’t be presented in today’s Office Framework naturally, even in the latest Office 2007, only parts of UIs can be hosted into Ribbons, Task Panes, etc., which is far from enough for enterprise applications. Is there any way to solve such question? Obviously, once this question is solved, the software such as Office System will save a lot of costs in time and money when we develop something based on it. From the technology conceit, Tangram Extension Tools for Application is just designed for such questions. One of its design purposes is enabling developers present many software UI elements in the software system similar to MS Office.

5. Using Tangram Extension Tools for Application Extend Microsoft Office 2007

The Demo Sample of how to use Tangram Extension Tools for Application is based on the latest version VSTO (which is provided in Visual Studio 2008). This Demo Project is as subdirectory “Tangram\TangramWordVBAddIn

5.1 Open Visual Studio 2008 and create a VSTO VB project

At first, you need to create a basic VSTO WordAddin project based on Visual Basic .NET.

5.2 Add a reference to the TangramCommonExtender component;

TangramCommonExtender is the key component of Tangram Extension Tools for Application. By using this component, developer can implement hosting a .NET WinForm as UI element into the target software system. In this paper, we use this component to host .NET WinForm objects as a part of Word 2007 software UI frame.

5.3 Add a Ribbon object;

Using class wizard add a Ribbon component to this project.

We get a WordAddin project with a Ribbon designer.

Add two Button objects to the Ribbon component, and then modify the value of ‘ControlIDType’ property of the Tab1 object on Ribbon to ‘Custom’.

Double click two added Ribbon Button objects; the following code window is displayed.

5.4 Prepare xtml files;

Copy two xtml files(desktop.xtml and desktop4.xtml) provided in the source code(which at subdirectory “Tangram\xtml”) to the ‘c:\’. Of course, you can place them into the other directory that you specify. For details about xtml files, see Overview of Tangram Extension Tools for Application section in this paper.

5.5 Modify the class Ribbon1

Modify the source code of the class Ribbon1 as below:

Public Class Ribbon1
Dim RibbonNavigator As NewTangramNavigator
Private Sub Ribbon1_Load(ByVal sender As System.Object, ByVal e As RibbonUIEventArgs) Handles MyBase.Load
RibbonNavigator.SetMainClientID("_Wwf")
End Sub
Private Sub Ribbon1_Close(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Close
RibbonNavigator.Release()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) Handles Button1.Click
Dim xObj AsTangramDocObj
xObj = RibbonNavigator.NavigateXTML(0, "c:\desktop.xtml", True)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) Handles Button2.Click
Dim xObj AsTangramDocObj
xObj = RibbonNavigator.NavigateXTML(0, "c:\desktop4.xtml", True)
End Sub
End Class

We can give more detail explanations for above code. The first thing to note is that the ‘RibbonNavigator’ object is an instance of .NET class ‘TangramNavigator’ exposed by TangramCommonExtender assembly, which implements how to load an extended software frame to the target software system. This object contains two methods, the first one is “SetMainClientID” that takes a string parameter and is used to identify the ‘Windows Class Name’ of the client area window of the mainframe window. For a general MDI Window, the value of this string is “MDIClient”. For the common MS Office software, this value is:

1. “_Wwf” for MS Word;

2. “XLDesk” for Excel;

3. “Rctrl_renwnd32” for the original mainframe of Outlook;

4. “AfxWndW” for the other mainframes of Outlook;

Generally, we can obtain this string value for specific Windows Window by Spy++ tool provided with Visual Studio. The second method is ‘NavigateXTML’, which takes three parameters. The followings are the description of these parameters:

1.The first parameter is used to identify the handle of a mainframe window. The default active main frame will be found and selected as the specified main frame form if this parameter is zero;

2.The second parameter is an xtml file path. For details about xtml files, see Overview of Tangram Extension Tools For Application section in this paper;

3. The third parameter is BOOL type. The value of this parameter will be true if the work target which Tangram Extension Tools applied is a specific desktop software system; otherwise is false if your work target is “Windows Desktop”.

The Method ‘NavigateXTML’ completes the re-construction task of new client area. The previous client area window will be placed into the position of the UI corresponding to the node named “TangramMDIView” if the xtml file that NavigateXTML loads contains such a node. Other vacant positions will be populated with new UI elements, which are .NET WinForms in this sample. A mainframe can contain several extended UI frames; objects populated into each extended frame may be different elements depending on your needs. The second item of note is .NET Object “TangramDocObj” exposed by TangramCommonExtender assembly, when a xtml file is loaded by an instance of ‘TangramNavigator’ using its NavigateXTML method, we obtained a “TangramDocObj” object instance, some more detail information of “TangramDocObj” will be discussed later.

Compile it and run; the result is:

Click the first Ribbon button:

Click the second Ribbon button; the result is:

5.6 Place a .NET WinForm object into the client area of Word 2007

Now, we add a new WinForm object “Form1” to this project.

Modify the code of the Click event for Button1 in Ribbon object as below:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) Handles Button1.Click
Dim xObj AsTangramDocObj
xObj = RibbonNavigator.NavigateXTML(0, "c:\desktop.xtml", True)
If xObj.ObjectInstalled("MicrosoftWord_S0001") = False Then
Dim xForm As New Form1
xObj.SetWnd(xForm, "MicrosoftWord_S0001")
xForm.Show()
End If
End Sub
<p>Where, a key object is “TangramDocObj”, each xtml file is corresponding to a “TangramDocObj” object. Developers navigate an xtml file though a “TangramNavigator” object instance to obtain a “TangramDocObj” object instance, the .NET Object “TangramDocObj” contains two methods and two properties. The following describes the methods of “TangramDocObj” object:</p>

<p class="D30" style="MARGIN-LEFT: 63pt; TEXT-INDENT: -21pt; TEXT-ALIGN: left" align="left">1. ObjectInstalled, used to detect whether the specified Vacant Room is populated with .NET WinForm object. Its parameter is a string, which is the name of a Vacant Room(by double click the left key of mouse on a ‘Vacant Room’ can copy this value to clipboard);</p>

<p class="D30" style="MARGIN-LEFT: 63pt; TEXT-INDENT: -21pt; TEXT-ALIGN: left" align="left">2. SetWnd, takes two parameters. The first one is a string(just is the name of corresponding ‘Vacant Room’) used to specify a Vacant Room view; the second one is a WinForm object used to place into the specified Room.</p>

<p style="TEXT-ALIGN: left" align="left">Once Tangram Extension Tools for Application detects that one Room is not populated, it will placed a WinForm object into the specified position though method “SetWnd”.</p>

<p style="TEXT-INDENT: 21pt; TEXT-ALIGN: left" align="left">After compilation and clicking the first button on Ribbon object, the result is:</p>

<p style="TEXT-ALIGN: left" align="center"><img height="170" hspace="0" src="TangramExtensionToolsApp/image019.jpg" width="252" align="baseline" border="0" /></p>

<p style="TEXT-ALIGN: left" align="left">We can add multiple Form objects if there are Vacant rooms in the new re-constructed UI frame.</p>

<p style="MARGIN-LEFT: 18pt; TEXT-INDENT: -18pt; TEXT-ALIGN: left" align="left">5.7 Handle messages of the dialog box on the Form1 object</p>

<p>Generally, the above Form1 object don’t handle general messages of the dialog box properly, especially the Tab key message. For this reason, we need to modify the base class of the Form1 object to be “TangramForm”.
The following shows the process to modify: 
1. Open the file Form1.Designer.vb and locate the following code.</p>

<p style="MARGIN-LEFT: 105pt; TEXT-ALIGN: left" align="left">Partial Class Form1</p>

<p style="MARGIN-LEFT: 105pt; TEXT-ALIGN: left" align="left">Inherits System.Windows.Forms.Form</p>

<p style="TEXT-ALIGN: left" align="left">2. Replace Inherits System.Windows.Forms.Form with Inherits TangramForm.</p>

<p style="TEXT-ALIGN: left" align="left">3. Modify the code of the Click event of Button1 on Ribbon as below:</p>
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As Microsoft.Office.Tools.Ribbon.RibbonControlEventArgs) Handles Button1.Click
Dim xObj As TangramDocObj
xObj = RibbonNavigator.NavigateXTML(0, "c:\desktop.xtml", True)
If xObj.ObjectInstalled("MicrosoftWord_S0001") = False Then
Dim xForm As New Form1
xForm.TangramDoc = xObj
xObj.SetWnd(xForm, "MicrosoftWord_S0001")
xForm.Show()
End If
End Sub

Thus, the Form1 object can handle the messages of the dialog box properly. For detail codes, see implementation of the class “TangramForm” in TangramCommonExtender project.

5.8 Other applications for Office 2007

In the above sample, we take Word 2007 as an example and show you how to develop a project with Tangram Extension Tools for Application. For other application systems, especially Office family software, the development methods are similar and not intended to describe one by one here. Interested developers can refer other provided samples.

6. Overview of Tangram Extension Tools for Application

TangramDeskManager project is based on the MFC/ATL class library and contains the following key parts:

1, A XML Technology-Based Script Engine of UI Frames;

2, Two Asynchronous Pluggable Protocols for Internet Explorer;

3, An ActiveX Control: TangramWebCtrl.

6.1 A XML Technology-Based Description Engine for UI Frames

When you want to rebuild the client area of some software system, first of all, you should ensure that the features of the original client area can’t be destroyed and should treat it as a separate function unit. We must be aware that the structure of an extended frame may vary depending on needs when re-constructing the client area room. This means that a common solution with universality is needed. Generally, the complexity of an extended frame depends on the implementation technologies and development language, even the ability of developers to a certain extent. To be able to solve this problem commonly and avoid the difficulties resulted from the difference of technologies; the xml technology is leveraged in the Tangram framework. The XML Technology-Based Description Engine of UI Frames is the result of this thought. Generally, when a rectangle window is used as a user area, the base UI frame within it can be classified into two kinds of structures, one of which is a “Splitter structure” where it seems that the user area is divided into several sub-areas by “Splitter Bar”; the other kind of structure is a “Tabbed Window” structure that is commonly named a Tabbed window, which is different from Splitter. In a Tabbed Window structure, a set of user areas will be overlapped and the invisible user areas will be presented with a Tab. One common user area may contain both kinds of structures described as above. Generally, a Tabbed Window structure can be presented with various tab styles. However, only several simple tab styles are provided in the Tangram Extension Tools for Application. The following is an example of a UI frame:

Generally, it is difficult to implement the above UI with specific codes. This UI structure is implemented with XML in Tangram Extension Tools for Application as follow:

<Window>
<TangramNode Name="VBDoc" ID="tangramtabwnd" Width="771" Style="1" ActivePage="0">
<Pages>
<TangramNode Name="VBDoc_Tab00" Caption="TabPage1" ID="tangramsplitter" Width="762" >
<Row>
<TangramNode Name="VBDoc_Tab00_S0000" ID="TangramDesignView" Width="175" Height="590"/>
<TangramNode Name="VBDoc_Tab00_S0001" ID="tangramsplitter" Width="761" Height="590"/>
<Row>
<TangramNode Name="VBDoc_Tab00_S0001_S0000" ID="tangramexceltabwnd" Width="761" Style="0" ActivePage="0" Height="388"/>
<Pages>
<TangramNode Name="VBDoc_Tab00_S0001_S0000_Tab00" Caption="ExcelPage1" ID="tangrammdiview" Width="761" Height="371"/>
<TangramNode Name="VBDoc_Tab00_S0001_S0000_Tab01" Caption="ExcelPage2" ID="TangramDesignView" Width="603"/>
</Pages>
</TangramNode>
</Row>
<Row>
<TangramNode Name="VBDoc_Tab00_S0001_S0100" ID="TangramDesignView" Width="761" Height="195"/>
</Row>
</TangramNode>
</Row>
</TangramNode>
<TangramNode Name="VBDoc_Tab01" Caption="TabPage2" ID="tangramsplitter" Width="762" >
<Row>
<TangramNode Name="VBDoc_Tab01_S0000" ID="TangramDesignView" Width="257" />
<TangramNode Name="VBDoc_Tab01_S0001" ID="tangramoutlookview" Width="494" ActivePage="0">
<Pages>
<TangramNode Name="VBDoc_Tab01_S0001_Tab00" Caption="OutLookPane" ID="TangramDesignView" Width="494" />
<TangramNode Name="VBDoc_Tab01_S0001_Tab01" Caption="OutLookPane1" ID="TangramDesignView" Width="494" />
</Pages>
</TangramNode>
</Row>
</TangramNode>
</Pages>
</TangramNode>
</Window>

We can avoid a lot of coding work and implement a consistent UI description schema by using xml description. However, when the UI frame becomes complicated, writing xml files will become a new problem and difficulty, one of key purposes of TangramDeskManager is to render the above xml description as a software UI structure and implement visual-designer of an xml frame.

Xml files like above are called xtml files, each of which is corresponding to a customizable UI structure. One of the base thoughts of the Tangram system is: Developers design xtml files, and then placed objects, such as .NET Control/Form, MFC View or ActiveX controls, etc., into the Rooms identified with specified names. The specific process is: when a developer selects the client area in the target system, he would assume that this client area is removable, and then re-construct it. Thus, the area that is previously monopolized by the original client area is re-constructed. During that time, the developer can use the Splitter, Tabbed Window, etc. structures described as above to re-construct this target area. After re-construction, the original client area will occupy one specified Room in the new frame (Notes that it completely monopolizes the target area before re-construction), new generated Rooms will be populated with new UI elements. One of the major responsibilities of the Tangram Extension Tools for Application is to provide the visual-designer for writing xtml files.

6.2 Two Asynchronous Pluggable Protocols and Visualization design of xtml files

One of the original targets of Tangram Extension Tools is Internet Explorer. By using this tool, developers can design the IE Band object freely and customize its client area structure freely. Each xtml file can be rendered as a specific IE Band object (depend on the loading mode).

The XTML Visual designer is implemented as an Asynchronous Pluggable Protocol of IE. MFC/ATL developers can refer to the detail implementation of CTangramCMD class. By using the URL “ie:dc” in the address bar of IE, Developers can active the visual designer:

Press button NewXTML, a specific design page will be displayed as below:

Where, the context menu is activated by right clicking the mouse. The purpose of visual-designer is to provide a uniform design scenario. The menu item “Host Client…” is used to specify the position of the client area of the target software. With this visual designer, developers can design a vacant UI frame, the vacant Rooms of this frame will be populated with .NET WinForms during software design, double click on a vacant Room, the Name of it will be fetched (copied to the clipboard pad). And then, developer can bind a .NET WinForm Object to this vacant Room by using this name though the “TangramDocObj” object.

Another Asynchronous Pluggable Protocol contained in TangramDeskManager is used to load an xtml file. An xtml file can be loaded to the following 3 positions if the target software is Internet Explorer:

1. ExplorerBar in the left;

2.Communication Bar in the bottom;

3.The client area of IE;

The URL syntax is:

xtml://xtml file path?target = x where, x may be l, b or c.

For example, the URL “xtml://c:\desktop.xtml?target=c” can be rendered as below:

6.3 The ActiveX control TangramWebCtrl in TangramDeskManager

We don’t go into detail on this control here. Another article will provide more information on its applications.

7. Further discuss about Xtml files and Office development

Now that you’ve written and explored your first Office Extension application with Tangram Extension Tools for Application, let’s discuss this problem further. Once the frame of the client area in target software can be rendered with an xtml file, the target software will evolve to be another kind of browser which browses xtml files. The target software may not just be MS Office, it can also be another application system that supports plug-in technology. Other than general browsers, target software like Office is designed for rich client elements with UI frames, instead of common html files. For example, by browsing an xtml file Outlook Contact module can be extended as below:

When a contact is created in Outlook, only limit information can be presented. With xtml description technology, you can easily present more useful information on that contact, such as his/her performance, resume, etc., most of which Outlook has not considered. Excel is one of the software systems in most common use for enterprises and can be used to process many problems, such as huge data analysis, report and financial accounting, etc. In fact, many problems can be solved effectively in the Excel if the main interface of the enterprise information system can be built into Microsoft Excel directly. However, desktop UI structures are so many and rich, can they be loaded into Excel? With Tangram Extension Tools for Application, you can use Excel as a Browser to browse rich client pages. Thus, many enterprise application models can be hosted into the Excel frame directly.

(The new extended frame of Excel, which makes Excel become a rich client framework.)

If some Complex UI Structure can be presented as xtml files, then those software which can be treated as target software discussed above will become a highly customizable Application Browser (Browsing xtml files just like Internet Explorer browsing html files), this is a new route for improving the reusability of software and providing new extension methods for application software just like MS Office.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

Share

About the Author

sunhui
Web Developer
China China
No Biography provided

Comments and Discussions

 
GeneralMy vote of 1 Pinmemberahosie9-Feb-11 15:57 
GeneralHi Pinmemberdefineconst7-Oct-10 23:07 
Generala good article Pinmemberalex haifeng31-Jan-10 19:37 
GeneralGreat solution! PinmemberGil Klod9-Jan-09 11:56 
GeneralRe: Great solution! Pinmembersunhui9-Jan-09 12:03 
GeneralAbout .Net Port PinmemberIzzet Kerem Kusmezer8-Jul-08 11:12 
GeneralProvide link for SPY++ Pinmember~Khatri Mitesh~8-Jul-08 4:23 
GeneralWOW!!! PinmemberWcohen4-Jan-08 6:14 

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.141022.2 | Last Updated 24 Dec 2007
Article Copyright 2007 by sunhui
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid