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

DHTML User Interface Library

, 1 Mar 2013
Rate this:
Please Sign up or sign in to vote.
Implement an advanced DHTML user interface in your own MFC applications

Current Version: DHTMLUI v1.00 build 47

Index

Introduction

Have you ever wanted to make an application similar to Microsoft« Outlook Express« without resorting to ATL? The DHTMLUI library allows you to implement such an advanced DHTML user interface in your own MFC applications! This library is the latest version in a series of continuously updated classes which I have been using in one of my own projects. DHTMLUI started life as a part of my original application, but when my project crested more than 800K of raw source code, I decided to break my code into bite size chunks and so DHTMLUI was born.

    Microsoft« Outlook Express«
    Microsoft« Outlook Express«

My previous article, "Processing HTML Forms From a CHtmlView", shows a very basic technique for retrieving form data using a standard CHtmlView. This technique is fine for basic forms, but what if you want to notify your program when a selection is made from a list of radio buttons? Well, this library makes this all possible!

NOTE: This library is by no means what I would consider to be complete! There are classes in which functions have been defined, but there is no actual code in them. This is a result of laziness on my part! If you need to use a particular function and it has no code, let me know and I will fill in the details for you, unless of course you want to do it! Please submit a copy of any changed files to me via e-mail - crowtc@gmail.com - and I will make the changes to the master copy.

About the DHTMLUI Library

The DHTMLUI Library simplifies the use of the myriad COM methods and properties used in conjunction with a browser window. The library also allows you to override the functionality associated with almost every event, feature request and property change. This library allows you to implement almost every feature present in Internet Explorer! This kind of power comes at a cost though, browsing through the library source code is like trying to read a popular novel that has been translated into Old English!

This library is based on information I have collected from various sources, including the Microsoft Internet Explorer 5.5 SDK, MSDN and the Platform SDK. There are bits and pieces from Microsoft samples, pieces gleaned from numerous websites and a lot of my own "This function isn't documented, but let's see what I can do with it" original code.

Enjoy!

Using the DHTMLUI Library

Getting Started

Before using this library, you should make sure you have the Platform SDK installed and the paths are set in your Options...Directories tab. If you want to use Internet Explorer 5.x features, you want to make sure the SDK is installed as well, but it is not 100% necessary for normal operation. To make everything work, you must also have the corresponding version of Internet Explorer installed!

Extract the Library

Extract the DHTMLUI Library where you want, but be sure to configure the path in your directories tab.

Open and Compile the Project

Open the DHTMLUI workspace and open the class labeled __DHTMLUI_Config, or DHTMLUIConfig.h. This class is a dummy class to help me open the configuration file (lazy huh?). Well, anyway - go through the file and set the options for the library, it is pretty well documented in the file and should be pretty easy to do.

Save the file and do a complete rebuild both Debug and Release configurations, just to make sure they compile correctly. If they don't compile, please check the library dependencies before flaming me or blasting my email with epithets that would make a "Hell's Angel" ask to leave the room.

When you get it to compile, you may continue on with the next step.

Setting up your Project

I made this library to be used as a drop-in replacement for CHtmlView, so setting it up in an existing project is pretty easy. If you don't have an existing project, use the MFC AppWizard to create a project which uses Automation and set up the application's primary view as a CHtmlView. If your existing project does not have automation enabled, you will only need to add it if you want your embedded DHTML pages to be able to access your application via COM.

Once you have a project with a CHtmlView you will need to add the following lines (Bold) to the project's STDAFX.H file if they aren't already there:

// stdafx.h : include file for standard system include files,
//  or project specific include files that are used frequently, but
//      are changed infrequently
//

#if !defined(AFX_STDAFX_H__1F9F46AD_DDF4_4D29_BC06_592204E7F660__INCLUDED_)
#define AFX_STDAFX_H__1F9F46AD_DDF4_4D29_BC06_592204E7F660__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define VC_EXTRALEAN        // Exclude rarely-used stuff from Windows headers

#include <afxwin.h>         // MFC core and standard components
#include <afxext.h>         // MFC extensions
#include <afxadv.h>
#include <afxdisp.h>        // MFC Automation classes

#ifndef _AFX_NO_DB_SUPPORT
#include <afxdb.h>          // MFC ODBC database classes
#endif // _AFX_NO_DB_SUPPORT

#ifndef _AFX_NO_DAO_SUPPORT
#include <afxdao.h>         // MFC DAO database classes
#endif // _AFX_NO_DAO_SUPPORT

#include <afxdtctl.h>       // MFC support for Internet Explorer 4 Common 
                            // Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h>         // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
#include <afxhtml.h>        // MFC HTML view support

#include <dhtmlui.h>        // Dynamic HTML User Interface Library

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately 
// before the previous line.

#endif //!defined(AFX_STDAFX_H__1F9F46AD_DDF4_4D29_BC06_592204E7F660__INCLUDED_)

    In your CHtmlView derived class header file, add a define to replace CHtmlView with CHtmlViewEx. This enables you to keep using the name CHtmlView when you refer to the class and there is a lot less typing involved.

    /////////////////////////////////////////////////////////////////////////////
    
    #define CHtmlView CHtmlViewEx
    
    /////////////////////////////////////////////////////////////////////////////
    
    class CWorksheetView : public CHtmlView
    {
    protected: // create from serialization only
        CWorksheetView();
        DECLARE_DYNCREATE(CWorksheetView)
    
    ...
    

      In your CDocument class, you should have an automation interface, this is where you will add property and method extensions to DHTML. The methods you add here will become available to JavaScript and VBScript through the window.external interface.

      Basically, if you add a method called LoadFormData defined as:

         afx_msg void LoadFormData( long PageNumber );
      
      ------
      
         void CWorksheetDoc::LoadFormData(long PageNumber)
         {
            GET_CURRENT_VIEW(pView);
      
            switch(PageNumber)
            {
               case 1:
          ...
               default:
                  break;
            }
         }
         

      You can call LoadFormData from your embedded web pages as such:

         <script language="JavaScript">
         <!--
      
         function window_onload( page )
         {
            window.external.LoadFormData( page );
         }
      
         //-->
         </script>
      

      You do basically the same thing for properties, except that return values of non-integral types are usually passed by reference.

      Special Features of this Library

      The DHTMUI Library has a number of capabilities which set it apart from CHtmlView. The number of features is too great to go into much detail on each of them, so I will include some of the header files and you can read more about them in the source code documentation.

      // HtmlViewEx.h : header file
      //
      //////////////////////////////////////////////////////////////////
      
      #ifndef __HTMLVIEWEX_H__
      #define __HTMLVIEWEX_H__
      
      #if _MSC_VER >= 1000
      #pragma once
      #endif // _MSC_VER >= 1000
      
      #ifndef __mshtmhst_h__
          #include <mshtmhst.h>
      #endif
      
      #include <mshtml.h>            // IE/MSHTML Interface Definitions
      
      // Forward Declarations
      class CHtmlViewExOccManager;
      
      // The available commands
      #define HTMLID_FIND 1
      #define HTMLID_VIEWSOURCE 2
      #define HTMLID_OPTIONS 3
      
      // Names for SetSecureLockIcon() values
      #define SECURELOCKICON_UNSECURE         0
      #define SECURELOCKICON_MIXED        1
      #define SECURELOCKICON_SECURE_UNKNOWNBITS    2
      #define SECURELOCKICON_SECURE_40BIT        3
      #define SECURELOCKICON_SECURE_56BIT        4
      #define SECURELOCKICON_SECURE_FORTEZZA    5
      #define SECURELOCKICON_SECURE_128BIT        6
      
      // Kill some of the MFC garbage
      #undef  AFX_DATA
      #define AFX_DATA
      
      
      ///////////////////////////////////////////////////////////////////
      // CHtmlViewEx class
      
      class _INS_EXT_CLASS CHtmlViewEx : public CFormView
      {
          DECLARE_DYNCREATE(CHtmlViewEx)
      
      ///////////////////////////////////////////////////////////////////
      // Construction
      ///////////////////////////////////////////////////////////////////
      public:
          CHtmlViewEx();
      
      ///////////////////////////////////////////////////////////////////
      // Attributes
      ///////////////////////////////////////////////////////////////////
      protected:
          CHtmlViewExOccManager* m_pHtmlViewExOccManager;
          int m_nFontSize;
          BOOL m_bNoStatusText;
          BOOL m_bOfflineIfNotConnected;
          BOOL m_bSilentMode;
          CString m_strUserAgent;
      
      public:
          void        SetNoStatusText(BOOL bNoStatus = TRUE);
          int        GetFontSize() const;
          void        SetFontSize(int fontSize = 2);
          CString        GetType() const;
          long        GetLeft() const;
          void        SetLeft(long nNewValue);
          long        GetTop() const;
          void        SetTop(long nNewValue);
          long        GetHeight() const;
          void        SetHeight(long nNewValue);
          void        SetVisible(BOOL bNewValue);
          BOOL        GetVisible() const;
          CString        GetLocationName() const;
          READYSTATE    GetReadyState() const;
          BOOL        GetOffline() const;
          void        SetOffline(BOOL bNewValue);
          BOOL        GetSilent() const;
          void        SetSilent(BOOL bNewValue);
          BOOL        GetTopLevelContainer() const;
          CString        GetLocationURL() const;
          BOOL        GetBusy() const;
          LPDISPATCH    GetApplication() const;
          LPDISPATCH    GetParentBrowser() const;
          LPDISPATCH    GetContainer() const;
          LPDISPATCH    GetHtmlDocument() const;
          CString        GetFullName() const;
          int        GetToolBar() const;
          void        SetToolBar(int nNewValue);
          BOOL        GetMenuBar() const;
          void        SetMenuBar(BOOL bNewValue);
          BOOL        GetFullScreen() const;
          void        SetFullScreen(BOOL bNewValue);
          OLECMDF        QueryStatusWB(OLECMDID cmdID) const;
          BOOL        GetRegisterAsBrowser() const;
          void        SetRegisterAsBrowser(BOOL bNewValue);
          BOOL        GetRegisterAsDropTarget() const;
          void        SetRegisterAsDropTarget(BOOL bNewValue);
          BOOL        GetTheaterMode() const;
          void        SetTheaterMode(BOOL bNewValue);
          BOOL        GetAddressBar() const;
          void        SetAddressBar(BOOL bNewValue);
          BOOL        GetStatusBar() const;
          void        SetStatusBar(BOOL bNewValue);
          CString        GetUserAgent() const;
          void        SetUserAgent(LPCTSTR strNewValue);
      
      ///////////////////////////////////////////////////////////////////
      // Operations
      ///////////////////////////////////////////////////////////////////
      
      public:
      #ifdef _DEBUG
          virtual void AssertValid() const;
          virtual void Dump(CDumpContext& dc) const;
      #endif
      
      ///////////////////////////////////////////////////////////////////
      // New CHtmlViewEx Operations
      //
      public:
          // Helper for OLE Commands to the WebBrowser
          void        ExecCmdTarget(DWORD nCmdID);
      
          // Helper for parsing POST Data
          CString        GetValueFromPostData(LPCTSTR strPostData, 
                                              LPCTSTR strValName);
      
          ///////////////////////////////////////////////////////////////////
          // Setup Functions
          ///////////////////////////////////////////////////////////////////
          // These functions are primarily for doing the initial setup
          // of a form upon load.  Most other actions should be performed
          // within the form page itself.
          ///////////////////////////////////////////////////////////////////
      public:
          IDispatch*    GetInputElementByName(LPCTSTR lpszElementName);
          IDispatch*    GetSelectElementByName(LPCTSTR lpszElementName);
          IDispatch*    GetTextAreaElementByName(LPCTSTR lpszElementName);
      
      protected:
          IHTMLOptionElementFactory*    GetOptionElementFactory();
      
      public:
          ///////////////////////////////////////////////////////////////////
          // General Input Controls
          BOOL        SetInputTextValue(LPCTSTR lpszFieldName, LPCTSTR lpszValue);
          CString     GetInputTextValue(LPCTSTR lpszFieldName);
      
          ///////////////////////////////////////////////////////////////////
          // Drop-down list / list box
          BOOL        RemoveAllOptionElements(LPCTSTR lpszFieldName);
          BOOL        AddOptionElement(LPCTSTR lpszFieldName, 
                                       LPCTSTR lpszOptionText, 
                                       LPCTSTR lpszOptionValue = NULL,
                                       BOOL bSelected = FALSE, 
                                       BOOL bDefault = FALSE,
                                       long nBefore = -1);
          BOOL        ClearSelection(LPCTSTR lpszFieldName);
          BOOL        SetOptionSelected(LPCTSTR lpszFieldName,
                                        LPCTSTR lpszOptionText);
      
          ///////////////////////////////////////////////////////////////////
          // Checkbox Specific
          BOOL        SetCheck(LPCTSTR lpszFieldName);
          BOOL        ClearCheck(LPCTSTR lpszFieldName);
      
          ///////////////////////////////////////////////////////////////////
          // Regular Button Specific
          BOOL        SetButtonAction(LPCTSTR lpszFieldName, LPCTSTR lpszAction);
      
          ///////////////////////////////////////////////////////////////////
          // Radio Button Specific
          BOOL        SetRadioSelected(LPCTSTR lpszFieldName, BOOL bSelected);
          BOOL        SetRadioDisabled(LPCTSTR lpszFieldName, BOOL bDisabled);
      
      public:
          ///////////////////////////////////////////////////////////////////
          // NOTE: If you use these functions, you must navigate to a
          //       page for them to take effect!
          //
          // Use "Navigate2(GetLocationURL(), 0, NULL, NULL);" to navigate
          // to the page currently displayed
          ///////////////////////////////////////////////////////////////////
      
          ///////////////////////////////////////////////////////////////////
          // DocHostUIHandler DoubleClick interface functions
          DWORD        GetUI_DblClk() const;
          void        SetUI_DblClk(DWORD dwSet);
      
          ///////////////////////////////////////////////////////////////////
          // DocHostUIHandler Flags interface functions
          DWORD        GetUI_Flags() const;
          void        SetUI_Flags(DWORD dwSet);
      
          BOOL        GetUIFlag_Dialog() const;
          BOOL        GetUIFlag_DisableHelpMenu() const;
          BOOL        GetUIFlag_No3dBorder() const;
          BOOL        GetUIFlag_NoScrollbar() const;
          BOOL        GetUIFlag_DisableScriptInactive() const;
          BOOL        GetUIFlag_OpenNewWin() const;
          BOOL        GetUIFlag_DisableOffscreen() const;
          BOOL        GetUIFlag_FlatScrollbar() const;
          BOOL        GetUIFlag_DivBlockDefault() const;
          BOOL        GetUIFlag_ActivateClientHitOnly() const;
      
          void        SetUIFlag_Dialog(BOOL bSet);
          void        SetUIFlag_DisableHelpMenu(BOOL bSet);
          void        SetUIFlag_No3dBorder(BOOL bSet);
          void        SetUIFlag_NoScrollbar(BOOL bSet);
          void        SetUIFlag_DisableScriptInactive(BOOL bSet);
          void        SetUIFlag_OpenNewWin(BOOL bSet);
          void        SetUIFlag_DisableOffscreen(BOOL bSet);
          void        SetUIFlag_FlatScrollbar(BOOL bSet);
          void        SetUIFlag_DivBlockDefault(BOOL bSet);
          void        SetUIFlag_ActivateClientHitOnly(BOOL bSet);
      
      ///////////////////////////////////////////////////////////////////
      // Basic CHtmlView Operations
      //
      public:
          void        GoBack();
          void        GoForward();
          void        GoHome();
          void        GoSearch();
          void        Navigate(LPCTSTR URL, DWORD dwFlags = 0, 
                               LPCTSTR lpszTargetFrameName = NULL, 
                               LPCTSTR lpszHeaders = NULL, 
                               LPVOID lpvPostData = NULL, DWORD dwPostDataLen = 0);
          void        Navigate2(LPITEMIDLIST pIDL, DWORD dwFlags = 0, 
                                LPCTSTR lpszTargetFrameName = NULL);
          void        Navigate2(LPCTSTR lpszURL, DWORD dwFlags = 0, 
                                LPCTSTR lpszTargetFrameName = NULL, 
                                LPCTSTR lpszHeaders = NULL, 
                                LPVOID lpvPostData = NULL, DWORD dwPostDataLen = 0);
          void        Navigate2(LPCTSTR lpszURL, DWORD dwFlags, 
                                CByteArray& baPostedData, 
                                LPCTSTR lpszTargetFrameName = NULL, 
                                LPCTSTR lpszHeader = NULL);
          void        Refresh();
          void        Refresh2(int nLevel);
          void        Stop();
          void        PutProperty(LPCTSTR lpszProperty, const VARIANT& vtValue);
          void        PutProperty(LPCTSTR lpszPropertyName, double dValue);
          void        PutProperty(LPCTSTR lpszPropertyName, LPCTSTR lpszValue);
          void        PutProperty(LPCTSTR lpszPropertyName, long lValue);
          void        PutProperty(LPCTSTR lpszPropertyName, short nValue);
          BOOL        GetProperty(LPCTSTR lpszProperty, CString& strValue);
          COleVariant     GetProperty(LPCTSTR lpszProperty);
          void        ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt, 
                             VARIANT* pvaIn, VARIANT* pvaOut);
          BOOL        LoadFromResource(LPCTSTR lpszResource);
          BOOL        LoadFromResource(UINT nRes);
      
      ///////////////////////////////////////////////////////////////////
      // Overrides
      ///////////////////////////////////////////////////////////////////
          // ClassWizard generated virtual function overrides
          //{{AFX_VIRTUAL(CHtmlViewEx)
          public:
          virtual void OnDraw(CDC* pDC);
          virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName,
                              DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, 
                              UINT nID,CCreateContext* pContext = NULL);
          virtual BOOL OnAmbientProperty(COleControlSite* pSite, DISPID dispid, 
                                         VARIANT* pvar);
          //}}AFX_VIRTUAL
      
      ///////////////////////////////////////////////////////////////////
      // Overridable Event Notifications
      //
      public:
          virtual void OnNavigateComplete2(LPCTSTR strURL);
          virtual void OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags,    
                                         LPCTSTR lpszTargetFrameName, 
                                         LPCTSTR strPostedData,    
                                         LPCTSTR lpszHeaders, BOOL* pbCancel);
          virtual void OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags,
                                         LPCTSTR lpszTargetFrameName, 
                                         CByteArray& baPostedData,    
                                         LPCTSTR lpszHeaders, BOOL* pbCancel);
          virtual void OnStatusTextChange(LPCTSTR lpszText);
          virtual void OnProgressChange(long nProgress, long nProgressMax);
          virtual void OnCommandStateChange(long nCommand, BOOL bEnable);
          virtual void OnDownloadBegin();
          virtual void OnDownloadComplete();
          virtual void OnTitleChange(LPCTSTR lpszText);
          virtual void OnPropertyChange(LPCTSTR lpszProperty);
          virtual void OnNewWindow2(LPDISPATCH* ppDisp, BOOL* Cancel);
          virtual void OnDocumentComplete(LPCTSTR lpszURL);
          virtual void OnQuit();
          virtual void OnVisible(BOOL bVisible);
          virtual void OnToolBar(BOOL bToolBar);
          virtual void OnMenuBar(BOOL bMenuBar);
          virtual void OnStatusBar(BOOL bStatusBar);
          virtual void OnFullScreen(BOOL bFullScreen);
          virtual void OnTheaterMode(BOOL bTheaterMode);
          virtual void OnFilePrint();
      
          // Formerly unimplemented
          virtual void OnAddressBar(BOOL bAddressBar);
          virtual void OnAppCmd(LPCTSTR lpszAppCmd, LPCTSTR PostData);
          virtual void OnAdvancedContextMenu(DWORD dwID, CPoint ptPosition, 
                                             IUnknown* pCommandTarget, 
                                             IDispatch* pDispatchObjectHit);
          virtual void OnShowHelp(HWND hwnd, LPCTSTR pszHelpFile,
                                  UINT uCommand,DWORD dwData,POINT ptMouse,
                                  IDispatch __RPC_FAR *pDispatchObjectHit);
          virtual void OnShowMessage(HWND hwnd, LPCTSTR lpstrText,
                                     LPCTSTR lpstrCaption, DWORD dwType,
                                     LPCTSTR lpstrHelpFile, DWORD dwHelpContext, 
                                     LRESULT __RPC_FAR *plResult);
          virtual void OnViewSource();
          virtual void OnToolsInternetOptions();
          virtual void OnEditCut();
          virtual void OnEditCopy();
          virtual void OnEditPaste();
          virtual void OnEditSelectall();
          virtual void OnEditFindOnThisPage();
          virtual void OnWindowSetResizable(BOOL Resizable);
          virtual void OnWindowClosing(BOOL IsChildWindow, BOOL* Cancel);
          virtual void OnWindowSetLeft(long left);
          virtual void OnWindowSetTop(long Top);
          virtual void OnWindowSetWidth(long Width);
          virtual void OnWindowSetHeight(long Height);
          virtual void OnClientToHostWindow(long* CX, long* CY);
          virtual void OnSetSecureLockIcon(long SecureLockIcon);
          virtual void OnFileDownload(BOOL* Cancel);
      
      ///////////////////////////////////////////////////////////////////
      // Implementation
      ///////////////////////////////////////////////////////////////////
      protected:
          IWebBrowser2* m_pBrowserApp;
      
      public:
      
          virtual ~CHtmlViewEx();
          CWnd m_wndBrowser;
      
      ///////////////////////////////////////////////////////////////////
      // Event reflectors (not normally overridden)
      protected:
          virtual void NavigateComplete2(LPDISPATCH pDisp, VARIANT* URL);
          virtual void BeforeNavigate2(LPDISPATCH pDisp, VARIANT* URL, 
                                       VARIANT* Flags, VARIANT* TargetFrameName, 
                                       VARIANT* PostData, VARIANT* Headers,
                                       BOOL* Cancel);
          virtual void DocumentComplete(LPDISPATCH pDisp, VARIANT* URL);
      
      ///////////////////////////////////////////////////////////////////
      // Internal Helper Functions
      protected:
          char        CharTokenToChar(const CString &val);
          CString        ProcessCharCodes(LPCTSTR lpszInput);
          void        RemoveAllOptionElements_(IHTMLSelectElement* pSelectElem);
      
          // Custom UI Toggles
          void        UseCustomHelp(BOOL bSet);
          void        UseCustomMessage(BOOL bSet);
          void        UseCustomContextMenu(BOOL bSet);
          void        UseAdvancedContextMenu(BOOL bSet);
      
      ///////////////////////////////////////////////////////////////////
      // Generated message map functions
      protected:
          //{{AFX_MSG(CHtmlViewEx)
          afx_msg void OnSize(UINT nType, int cx, int cy);
          afx_msg void OnPaint();
          afx_msg void OnDestroy();
          //}}AFX_MSG
      
          DECLARE_MESSAGE_MAP()
          DECLARE_EVENTSINK_MAP()
      };
      
      #undef  AFX_DATA
      #define AFX_DATA
      
      /////////////////////////////////////////////////////////////////////////////
      //{{AFX_INSERT_LOCATION}}
      // Microsoft Developer Studio will insert additional declarations immediately
      // before the previous line.
      
      ///////////////////////////////////////////////////////////////////
      // Inline Functions (They looked too messy in this file)
      #include "HtmlViewEx.inl"
      
      #endif // __HTMLVIEWEX_H_
         

      In Conclusion

      As I said up above, this library is far from complete. If you have any bug fixes, comments or contributions to help make this library more complete, feel free to contact me via e-mail. You can do a LOT with the library just as it is, but as most code goes, it can always be better.

      You are free to use this library for anything, but if you are using it in an application that will be distributed commercially or for enterprise internal distribution, or want to include it in a larger library, you must contact me before you release it. I will not charge you for it, I just want to know where it's being used to consider providing full support for it.

      Thank You,

      Ted Crow
      Infinity Networking Solutions

License

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

About the Author

Ted Crow
Systems Engineer
United States United States
Ted has been programming computers since 1981 and networking them since 1984. He has been a professional technology manager and computer networking consultant for more than 20 years.
 
Feel free to connect with Ted on LinkedIn
Follow on   Twitter   LinkedIn

Comments and Discussions

 
GeneralHelp me please PinmemberMarmouse27-May-07 16:33 

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.140709.1 | Last Updated 2 Mar 2013
Article Copyright 2001 by Ted Crow
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid