/*++

Copyright (c) 1992  Microsoft Corporation

Module Name:

    Winmsd.c

Abstract:


Author:

    David J. Gilman  (davegi) 12-Nov-1992
    Gregg R. Acheson (GreggA)  7-Sep-1993

Environment:

    User Mode

--*/

#include "resource.h"
#include "dialogs.h"
#include "drives.h"
#include "environ.h"
#include "hardware.h"
#include "network.h"
#include "mem.h"
#include "msg.h"
#include "osver.h"
#include "resource.h"
#include "resprint.h"
#include "service.h"
#include "strresid.h"
#include "winmsd.h"
#include "computer.h"
#include "report.h"
#include "video.h"

#include <commctrl.h>
#include <commdlg.h>
#include <shellapi.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <tchar.h>
#include <windowsx.h>


//
// External Global Variables.
//

TCHAR  _lpszSelectedComputer [ COMPUTERNAME_LENGTH ];
HKEY   _hKeyLocalMachine = HKEY_LOCAL_MACHINE;
HKEY   _hKeyUsers = HKEY_USERS;
BOOL   _fIsRemote;


//
// Module handle.
//

HANDLE  _hModule;

//
// Application's icon handle.
//

HANDLE  _hIcon;


//
// Main window handle.
//

HANDLE  _hWndMain;

//
// Application's global ImageLists
//

HIMAGELIST  _h16x16Imagelist;      // 16x16 images
HIMAGELIST  _h32x32Imagelist;      // 32x32 images
HIMAGELIST  _hSystemImage;         // single image of system.bmp


//
// Internal Global Variables.
//

TCHAR g_szRunApp[MAX_PATH];    	// command line for the app selected in run dlg

//
// Application's accelerator table handle.
//

HANDLE  _hAccel;

//
// Internal function prototypes.
//

VOID Usage(
    VOID
    );

BOOL
InitializeApplication(
    INT         argc,
    CHAR        *argv[]
    );

void
InitImageLists( void );

BOOL
DoRunApplication( IN HWND hWnd );

BOOL
GetRunCommand (HWND hDlg,
      LPWSTR pszCommand,
      INT nMaxLen
      );

BOOL
GetRunHistoryCommand (HWND hDlg,
      LPWSTR pszCommand,
      INT nMaxLen
      );

BOOL
InitHistoryList (HWND hDlg);

BOOL
ReviseHistoryList (LPWSTR pszCommand);

BOOL StartProcess (LPWSTR pszApplication,
      LPWSTR pszParameters);


BOOL
MakeTabs(
      IN HWND hWnd,
      IN HWND hMainTabControl
      );

BOOL
GetTabClientRect( IN HWND hWndTab,
      IN LPRECT lpRect
      );


DLGTEMPLATE * WINAPI
DoLockDlgRes(LPWSTR lpszResName);

VOID
FixupNulls(LPWSTR p);


//
// Structure for the Run Application dialog
//

struct {

    UINT    iDisplayName;
    TCHAR   szExecutableName[MAX_PATH];

}   Tools[ ] = {

    {IDS_EVENTVWR,    TEXT( "eventvwr.exe" ) },
    {IDS_REGEDT32,    TEXT( "regedt32.exe" ) },
    {IDS_WINDISK,     TEXT( "windisk.exe"  ) },
	{IDS_TASKMGR,     TEXT( "taskmgr.exe"  ) },
    {IDS_PERFMON,     TEXT( "perfmon.exe"  ) },
    {IDS_CONTROLP,    TEXT( "control.exe"  ) },
    {IDS_NOTEPAD,     TEXT( "notepad.exe"  ) },
    {IDS_AUTOEXEC_NT, TEXT( "notepad.exe %systemroot%\\system32\\autoexec.nt" ) },
    {IDS_CONFIG_NT,   TEXT( "notepad.exe %systemroot%\\system32\\config.nt" ) },
    {IDS_EXPLORER,    TEXT( "explorer.exe" ) },
    {IDS_SYSTEDIT,    TEXT( "sysedit.exe"  ) }
    };

//
// Begin Code
//

VOID Usage(
    VOID
    )

{
    TCHAR szBuffer[1024];

    WFormatMessage(szBuffer, sizeof( szBuffer ), IDS_FORMAT_COMMAND_LINE_HELP);

    MessageBox( _hWndMain, szBuffer, GetString(IDS_APPLICATION_FULLNAME), MB_OK );

}



int
_CRTAPI1
main(
    INT         argc,
    CHAR        *argv[]
    )

/*++

Routine Description:

    Main is the entry point for Winmsd. It initializes the application and
    manages the message pump. When the message pump quits, main performs some
    global cleanup.

Arguments:

    None.

Return Value:

    int - Returns the result of the PostQuitMessgae API or -1 if
          initialization failed.

--*/

{
    MSG     msg;
    DLGHDR  *pHdr; 
	BOOL    bHandled;
	TCHAR   buffer[MAX_PATH];

    if( InitializeApplication( argc, argv )) {

		pHdr = (DLGHDR *) GetWindowLong( _hWndMain, GWL_USERDATA ); 

        while( GetMessage( &msg, NULL, 0, 0 )) {

			bHandled = FALSE;

			bHandled = TranslateAccelerator( _hWndMain, _hAccel, &msg );

			if (FALSE == bHandled)
			{
				if (pHdr->hwndDisplay)
				{
					bHandled = TranslateAccelerator(pHdr->hwndDisplay, _hAccel, &msg);
				}

				if (FALSE == bHandled && FALSE == IsDialogMessage(_hWndMain, &msg))
				{
					TranslateMessage(&msg);          // Translates virtual key codes

					DispatchMessage(&msg);           // Dispatches message to window
				}
			}
			
        }

        return msg.wParam;
    }

    //
    // Initialization failed.
    //

    return -1;
}


BOOL
InitializeApplication(
    INT         argc,
    CHAR        *argv[]
    )

/*++

Routine Description:

    InitializeApplication does just what its name implies. It initializes
    global varaibles, sets up global state (e.g. 3D-Controls), registers window
    classes and creates and shows the application's main window.

Arguments:

    None.

Return Value:

    BOOL    - Returns TRUE if the application succesfully initialized.

--*/

{
    WNDCLASS    Wc;
    ATOM        Window;
    OSVERSIONINFO vi;
    TCHAR       szBuffer[MAX_PATH];
    INT         nArg = 1;
    CHAR        *pch;
    BOOL        Success;
    DWORD       dwNumChars;
    INT         nDestination = 0;
    INT         nDetailLevel = 0;

    //
    // Make sure we are running NT 4.0 or greater
    //
    vi.dwOSVersionInfoSize  = sizeof( OSVERSIONINFO );

    GetVersionEx( &vi );

    if ((vi.dwMajorVersion < 4) ||
        (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)) {

        lstrcpy(szBuffer, GetString( IDS_NT_REQUIRED ) );

        MessageBox( NULL, szBuffer, GetString( IDS_APPLICATION_FULLNAME ), MB_ICONSTOP | MB_OK );

        return(FALSE);

    }

    //
    // Set the current machine name.
    //

    dwNumChars = sizeof(szBuffer);
    GetComputerName(szBuffer, &dwNumChars);

    wsprintf( _lpszSelectedComputer, L"\\\\%s", szBuffer);

    //
    // Collect the command line options, if any.
    //

    while( nArg < argc ){

      pch = argv[nArg];

      if ( *pch == '-' || *pch == '/') {

         pch++;

         switch( toupper( *pch ) ) {
         case 'S':
             nDetailLevel = IDC_SUMMARY_REPORT;
             break;

         case 'A':
             nDetailLevel = IDC_COMPLETE_REPORT;
             break;

         case 'P':
             nDestination = IDC_SEND_TO_PRINTER;
             break;

         case 'F':
             nDestination = IDC_SEND_TO_FILE;
             break;

         default:
             Usage();
             return(FALSE);

         }

         pch++;


      } else {

         if ( *pch == '\\') {

            MultiByteToWideChar( CP_ACP,
                  MB_PRECOMPOSED,
                  pch,
                  -1,
                  _lpszSelectedComputer,
                  sizeof(_lpszSelectedComputer)
                  );

            //
            // If the workstation service is not started, fail this attempt
            //

	        if (NERR_WkstaNotStarted == NetWkstaGetInfo( L"", 100L,(LPBYTE *) szBuffer ))
	        {
                //bugbug: we should throw up a messagebox here.
		        return FALSE;
	        }  

            Success = VerifyComputer( _lpszSelectedComputer );
            if (!Success) {
               return(FALSE);
            }

         }

      }

      nArg++;

    }

    //
    // Get the application's module (instance) handle.
    //

    _hModule = GetModuleHandle( NULL );
    DbgHandleAssert( _hModule );
    if( _hModule == NULL ) {
        return FALSE;
    }

    //
    // Load the application's main icon resource.
    //

    _hIcon = LoadIcon( _hModule, MAKEINTRESOURCE( IDI_WINMSD ));
    DbgHandleAssert( _hIcon );
    if( _hIcon == NULL ) {
        return FALSE;
    }

    //
    // Initialize the applications global image lists (helper.c)
    //

    InitImageLists();

    //
    // Load the application's accelerator table.
    //

    _hAccel = LoadAccelerators( _hModule, MAKEINTRESOURCE( IDA_WINMSD ));
    DbgHandleAssert( _hAccel );
    if(  _hAccel == NULL ) {
        return FALSE;
    }

    //
    // Register the window class for the application.
    //

    Wc.style            =   CS_HREDRAW
                          | CS_OWNDC
                          | CS_SAVEBITS
                          | CS_VREDRAW;
    Wc.lpfnWndProc      = MainWndProc;
    Wc.cbClsExtra       = 0;
    Wc.cbWndExtra       = DLGWINDOWEXTRA;
    Wc.hInstance        = _hModule;
    Wc.hIcon            = _hIcon;
    Wc.hCursor          = LoadCursor( NULL, IDC_ARROW );
    Wc.hbrBackground    = ( HBRUSH ) ( COLOR_BTNFACE + 1 );
    Wc.lpszMenuName     = NULL;
    Wc.lpszClassName    = L"Diagnostics";

    Window = RegisterClass( &Wc );
    DbgAssert( Window != 0 );
    if( Window == 0 ) {
        return FALSE;
    }

    //
    // Create the main window.
    //

    _hWndMain = CreateDialog(
                    _hModule,
                    MAKEINTRESOURCE( IDD_WINMSD ),
                    NULL,
                    MainWndProc
                    );

    DbgHandleAssert( _hWndMain );
    if( _hWndMain == NULL ) {
        return FALSE;
    }

    //
    // Set the window title.
    //

    wsprintf(szBuffer, L"%s - %s",
              GetString( IDS_APPLICATION_FULLNAME ),
              _lpszSelectedComputer);

    SetWindowText(_hWndMain, szBuffer);

    //
    // if we have been given a detail level or a destination on the
    // cmd line, then generate a report now, and terminate.
    //
    if( nDestination || nDetailLevel ){

       //
       // Make sure we have a destination
       //
       if ( !nDestination ) {
          nDestination = IDC_SEND_TO_FILE;
       }

       //
       // Make sure we have a detail level
       //
       if ( !nDetailLevel ) {
          nDetailLevel = IDC_SUMMARY_REPORT;
       }

       Success = GenerateReport ( _hWndMain, nDestination, IDC_ALL_TABS, nDetailLevel, TRUE );

       if(!Success){
          lstrcpy( szBuffer, GetString(IDS_REPORT_FAILED) );
          MessageBox(_hWndMain, szBuffer, GetString(IDS_APPLICATION_FULLNAME), MB_OK | MB_ICONSTOP );
       }

       return(FALSE);

   }

   //
   // Show the main window
   //

   ShowWindow( _hWndMain, SW_SHOW );


    return TRUE;
}

void
InitImageLists( void )
/*++

Routine Description:

    InitImageLists - create the image lists used by application

Arguments:

    none

Return Value:

    none

--*/
{

   // Create the 16 x 16 Image List
   _h16x16Imagelist = ImageList_LoadBitmap( _hModule,
                                           L"IDB_16x16",
                                           16,
                                           0,
                                           0x00808000);

   DbgHandleAssert( _h16x16Imagelist );


   // Create the 32 x 32 Image List
   _h32x32Imagelist = ImageList_LoadBitmap( _hModule,
                                           L"IDB_32x32",
                                           32,
                                           0,
                                           0x00808000);

   DbgHandleAssert( _h32x32Imagelist );

   // system image list (one item)
   _hSystemImage = ImageList_LoadBitmap( _hModule,
                                           L"IDB_SYSTEM",
                                           114,
                                           0,
                                           0x00FF00FF);

   DbgHandleAssert( _hSystemImage );

}

LRESULT
MainWndProc(
    IN HWND hWnd,
    IN UINT message,
    IN WPARAM wParam,
    IN LPARAM lParam
    )

/*++

Routine Description:

    MainWndProc processes messages for Winmsd's main window. This entails
    handling of messages from the menu bar.

Arguments:

    Standard WNDPROC entry.

Return Value:

    LRESULT - Depending on input message and processing options.

--*/

{
    BOOL        Success;
    PRINTDLG    PrtDlg;
    TCHAR       szBuffer[MAX_PATH];

    static
    HWND        hMainTabControl;

    static
    int         nCurrentTab;

    DLGHDR      *pHdr;

    switch( message ) {

	case WM_PAINT: 	
		{
			PAINTSTRUCT ps;
			RECT rc;

			//
			// Don't waste our time if we're minimized
			//

			if (FALSE == IsIconic(hWnd))
			{
				BeginPaint(hWnd, &ps);
				GetClientRect(hWnd, &rc);

				//
				// Draw an edge just below menu bar
				//

				DrawEdge(ps.hdc, &rc, EDGE_ETCHED, BF_TOP);
				EndPaint(hWnd, &ps);
			}

			break;
		}


    case WM_CREATE:
        {
            DWORD   cb;
            BOOL    Success;
            HKEY    hKey; 
            WINDOWPLACEMENT wp;
            DWORD   dwSize;
            DWORD   dwType;
            int     fDefault = TRUE;
            
            //
            // Read the window location in from the registry
            //
            if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,
                                  SZ_WINMSD_KEY,
                                  0,
                                  KEY_READ,
                                  &hKey))
            {
                fDefault = FALSE;

                dwSize = sizeof(wp);
 
                if (ERROR_SUCCESS != RegQueryValueEx(hKey,
                                                    L"Preferences", 
                                                    0, 
                                                    &dwType, 
                                                    (LPBYTE) &wp,
                                                    &dwSize)

                    // Validate type and size of options info we got from the registry

                    || dwType           != REG_BINARY
                    || dwSize           != sizeof(wp)

                    // Validate points

                    || wp.rcNormalPosition.left  > GetSystemMetrics(SM_CXMAXIMIZED)
                    || wp.rcNormalPosition.top   > GetSystemMetrics(SM_CYMAXIMIZED) )
        
                {
                     fDefault = TRUE;
                } 

                RegCloseKey( hKey ); 

            }  

            
            if (fDefault)
            {
                //
                // use default values
                //

                wp.rcNormalPosition.left = GetSystemMetrics( SM_CXSCREEN ) / 2 ;
                wp.rcNormalPosition.top  = GetSystemMetrics( SM_CYSCREEN ) / 2;

                //
                // Make it look good on my dual screen, I just hate
                // it being centered across two monitors.  This centers
                // it on the first monitor.
                //

                if (wp.rcNormalPosition.left > 1600) {
                   wp.rcNormalPosition.left = wp.rcNormalPosition.left / 2;
                }

                if (wp.rcNormalPosition.top > 1280) {
                   wp.rcNormalPosition.top = wp.rcNormalPosition.top / 2;
                }

                wp.rcNormalPosition.left = wp.rcNormalPosition.left - (((( LPCREATESTRUCT ) lParam )->cx ) / 2);
                wp.rcNormalPosition.top  = wp.rcNormalPosition.top -  (((( LPCREATESTRUCT ) lParam )->cy ) / 2);  

            }   

            Success = SetWindowPos(
                            hWnd,
                            NULL,
                            wp.rcNormalPosition.left,
                            wp.rcNormalPosition.top,
                            0,
                            0,
                              SWP_NOSIZE
                            | SWP_NOREDRAW
                            | SWP_NOZORDER
                            );
            DbgAssert( Success );

            return 0;
        }

    case WM_INITDIALOG:
        {
            //
            // Check for aliases
            //
            TCHAR szMessage[MAX_PATH];
            DWORD dwNumChars = MAX_PATH;

            if ( GetServerPrimaryName(&_lpszSelectedComputer[2], szBuffer, dwNumChars ) )
            {  
               wsprintf(szMessage, GetString(IDS_ALIAS_NAME), _lpszSelectedComputer, szBuffer);

               MessageBox( hWnd, szMessage, GetString( IDS_APPLICATION_FULLNAME ), MB_OK | MB_ICONINFORMATION );

               lstrcpy(&_lpszSelectedComputer[2], szBuffer);
            }   

            //
            // Get the handle of the tab control
            //
            hMainTabControl =  GetDlgItem( hWnd, IDC_MAIN_TAB );

            //
            // Fill out tab control with appropriate tabs
            //
            MakeTabs( hWnd, hMainTabControl );

            // Set Tab control to first tab
            pHdr = (DLGHDR *) GetWindowLong( hWnd, GWL_USERDATA );
            pHdr->hwndDisplay = CreateDialogIndirect( _hModule,
                    pHdr->apRes[ 0 ], hWnd, pHdr->ChildTabProc[ 0 ] );

            return( TRUE );

        }

    case WM_INITMENU:
        {
        // Call SHRestricted, @100 in shell32.dll
        HMODULE hModule = GetModuleHandle(L"Shell32");
        FARPROC SHRestricted = GetProcAddress( hModule, (LPCSTR) MAKEWORD(100,0));
        HMENU hMenu = GetMenu(_hWndMain);
        //
        // Remove restriced items from the menu
        //
        if (SHRestricted(0x00000001))
        {
	        DeleteMenu(hMenu, IDM_RUN_APPLICATION, MF_BYCOMMAND);
        }

        //
        // Remove restriced items from the menu
        //
        if (SHRestricted(0x00000080))
        {
	        DeleteMenu(hMenu, IDM_FILE_FIND_FILE, MF_BYCOMMAND);  	     
        }  

        //
        // Enable/Disable the "View Local" menu, based on whether we are 
        // local or not
        //
        EnableMenuItem(hMenu, IDM_VIEW_LOCAL, !_fIsRemote); 

        //
        // If the workstation service is not started, grey the Select Computer Menu
        //

	    if (NERR_WkstaNotStarted == NetWkstaGetInfo( L"", 100L,(LPBYTE *) szBuffer ))
	    {
		    EnableMenuItem(hMenu, IDM_SELECT_COMPUTER, MF_GRAYED);
	    }     

        DrawMenuBar(_hWndMain);

        break;
        }
    case WM_NOTIFY:
        {
            static
            int         nPreviousTab = 1;

            // switch on notification code

            switch ( ((LPNMHDR)lParam)->code ) { 

            case TCN_SELCHANGE:
				{
					TC_ITEM tci;
					int iSel;

					pHdr = (DLGHDR *) GetWindowLong( hWnd, GWL_USERDATA );

					iSel = TabCtrl_GetCurSel( pHdr->hwndTab );

					//
					//get the proper index to the appropriate procs
					//that were set in MakeTabs
					//
					tci.mask = TCIF_PARAM;
					TabCtrl_GetItem(pHdr->hwndTab, iSel, &tci);						

					// Destroy the current child dialog box, if any.
					if (pHdr->hwndDisplay != NULL)
					  DestroyWindow(pHdr->hwndDisplay);

					// Create the new child dialog box.
					pHdr->hwndDisplay = CreateDialogIndirect( 
							_hModule,
							pHdr->apRes[ tci.lParam ], 
							hWnd, 
							pHdr->ChildTabProc[ tci.lParam ] 
							);

					return(TRUE);
				}              

            case TTN_NEEDTEXT:
               {
                  LPTOOLTIPTEXT lpttt = (LPTOOLTIPTEXT) lParam;
                  int idCtrl = GetDlgCtrlID((HWND) ((LPNMHDR) lParam)->idFrom);	

                  lpttt->lpszText = (unsigned short *) IDS_APPLICATION_FULLNAME;
                  lpttt->hinst = _hModule;
                  return(TRUE);

               }

           }
           break;
        }


    case WM_COMMAND:
        {
            switch (LOWORD( wParam)) {

            // pass these messages on to the TabProc
            case IDC_PUSH_PROPERTIES:
            case IDC_PUSH_REFRESH:
               pHdr = (DLGHDR *) GetWindowLong( hWnd, GWL_USERDATA );

               PostMessage(pHdr->hwndDisplay,
                     message,
                     wParam,
                     lParam
                     );

               return TRUE;

            case IDM_COPY_TAB:
               if (GetKeyState(VK_SHIFT) & 0x8000) {

                  GenerateReport ( hWnd, IDC_CLIPBOARD, IDC_CURRENT_TAB, IDC_COMPLETE_REPORT, FALSE );

               } else {

                  GenerateReport ( hWnd, IDC_CLIPBOARD, IDC_CURRENT_TAB, IDC_SUMMARY_REPORT, FALSE );

               }
               break;

			case IDM_NEXTTAB:
			case IDM_PREVTAB:
				{
					int iSel;
					NMHDR nmhdr;

					pHdr = (DLGHDR *) GetWindowLong( hWnd, GWL_USERDATA );
					iSel = TabCtrl_GetCurSel( pHdr->hwndTab );

					// set the new tab
					iSel += (LOWORD( wParam) == IDM_NEXTTAB) ? 1 : -1; 

					// make sure we are not tabbing past legal limits
					if (iSel == TabCtrl_GetItemCount(pHdr->hwndTab)) 
					{
						iSel = 0;
					}
					else if (iSel < 0) 
					{
						iSel = (TabCtrl_GetItemCount(pHdr->hwndTab)) - 1;						
					}		

					TabCtrl_SetCurSel(pHdr->hwndTab, iSel);

					// SetCurSel doesn't do the page change (that would make too much
					// sense), so we have to fake up a TCN_SELCHANGE notification

					nmhdr.hwndFrom = GetDlgItem(_hWndMain, IDC_MAIN_TAB);
					nmhdr.idFrom   = IDC_MAIN_TAB;
					nmhdr.code     = TCN_SELCHANGE;
					
					SendMessage( hWnd, WM_NOTIFY, (WPARAM) IDC_MAIN_TAB, (LPARAM) &nmhdr);

					break;
				}

            case IDM_FILE_FIND_FILE:
               {
					// Call SHFindFile, @90 in shell32.dll
					HMODULE hModule = GetModuleHandle(L"Shell32");
					FARPROC pfn = GetProcAddress( hModule, (LPCSTR) MAKEWORD(90,0));

					if(pfn)
					{
						pfn( NULL, NULL);
					}

					break;
               }

            case IDM_RUN_APPLICATION:

                  Success = DoRunApplication( hWnd );
                  break;

            case IDM_WHATS_THIS:
                  PostMessage(hWnd, WM_SYSCOMMAND, SC_CONTEXTHELP, 0);
                  break;


            case IDC_PUSH_PRINT:
            case IDM_FILE_PRINT:
            case IDM_FILE_SAVE:
  
                //
                // Call the create report setup dialog.
                //
                DialogBoxParam(
                   _hModule,
                   MAKEINTRESOURCE( IDD_REPORT ),
                   hWnd,
                   ReportDlgProc,
                   LOWORD( wParam )
                   );
                 break;
                
            case IDOK:
            case IDM_FILE_EXIT:
                 PostMessage(hWnd, WM_CLOSE, 0, 0L);
                 break;

            case IDM_FILE_PRINT_SETUP:
                 //
                 // Call the Printer setup common dialog.
                 //
                 PrtDlg.lStructSize   = sizeof(PRINTDLG);
                 PrtDlg.hwndOwner     = hWnd;
                 PrtDlg.hDevMode      = NULL;
                 PrtDlg.hDevNames     = NULL;
                 PrtDlg.hDC           = NULL;
                 PrtDlg.Flags         = PD_PRINTSETUP;

                 PrintDlg ( &PrtDlg ) ;
                 return TRUE;

            case IDM_SELECT_COMPUTER:
				{
					TC_ITEM tci;
					TCHAR szBuffer[MAX_PATH];
					int iSel;

					//
					// Select Computer.
					//

					if( SelectComputer( hWnd, _lpszSelectedComputer ) )
					{	  
						pHdr = (DLGHDR *) GetWindowLong( hWnd, GWL_USERDATA );

						//
						// Recreate the tab control for the new machine
						//

						MakeTabs( hWnd, hMainTabControl );

						// Set Tab control to first tab
						pHdr = (DLGHDR *) GetWindowLong( hWnd, GWL_USERDATA );
						pHdr->hwndDisplay = CreateDialogIndirect( _hModule,
						pHdr->apRes[ 0 ], hWnd, pHdr->ChildTabProc[ 0 ] );

						return(TRUE);

					}

					return(FALSE);
				}

              case IDM_VIEW_LOCAL:
                 {
					 DWORD  cb;

					 //
					 // View local machine.
					 //

					 //
					 // Reset the pointer to HKEY_LOCAL_MACHINE and the fIsRemote flag
					 //

					 _fIsRemote = FALSE;
					 RegCloseKey( _hKeyLocalMachine );
					 _hKeyLocalMachine = HKEY_LOCAL_MACHINE;

                     RegCloseKey( _hKeyUsers );
					 _hKeyUsers = HKEY_USERS;


					 //
					 // Reset the window title
					 //

					 cb = sizeof(_lpszSelectedComputer);
					 GetComputerName(_lpszSelectedComputer, &cb);

					 wsprintf(szBuffer, L"Windows NT %s - \\\\%s",
						   GetString( IDS_APPLICATION_NAME ),
						   _lpszSelectedComputer);

					 Success = SetWindowText(hWnd, szBuffer);

					 DbgAssert( Success );

					 //
					 // Recreate the tab control for the new machine
					 //
					 
					 MakeTabs( hWnd, hMainTabControl );

					 // Set Tab control to first tab
					 pHdr = (DLGHDR *) GetWindowLong( hWnd, GWL_USERDATA );
					 pHdr->hwndDisplay = CreateDialogIndirect( 
							_hModule,
							pHdr->apRes[ 0 ], 
							hWnd, 
							pHdr->ChildTabProc[ 0 ] 
							);
					 
					 return TRUE;
                 }

            case IDM_HELP_ABOUT:
                 //
                 // Display the About dialog.
                 //
                 ShellAbout(
                     hWnd,
                     ( LPWSTR ) GetString( IDS_APPLICATION_NAME ),
                     INTERNAL_VERSION,
                     _hIcon
                     );

                 return TRUE;

            }
            break;

        }
    case WM_CLOSE:
        {
            DWORD dwDisposition;
            HKEY  hKey;
            WINDOWPLACEMENT wp;

            //
            // Do some clean up
            //
            pHdr = (DLGHDR *) GetWindowLong( hWnd, GWL_USERDATA );


            //
            // Save the window position to the registry
            //

            wp.length = sizeof(WINDOWPLACEMENT);

            GetWindowPlacement(hWnd, &wp);

            if (ERROR_SUCCESS == RegCreateKeyEx(HKEY_CURRENT_USER,
                                                SZ_WINMSD_KEY,
                                                0,
                                                TEXT("REG_BINARY"),
                                                REG_OPTION_NON_VOLATILE,
                                                KEY_WRITE,
                                                NULL,
                                                &hKey,
                                                &dwDisposition))
            {
                RegSetValueEx(hKey,
                              L"Preferences",
                              0,
                              REG_BINARY,
                              (LPBYTE) &wp,
                              sizeof(wp)); 

                RegCloseKey(hKey); 
            }  
            
            //
            // Close the registry keys
            //
            RegCloseKey(_hKeyLocalMachine);
            RegCloseKey(_hKeyUsers);

            //
            // Destroy Current tab
            //
            DestroyWindow(pHdr->hwndDisplay);

            //
            // Free memory associated with Tab structure
            //
            LocalFree( pHdr );

            //
            // Commit suicide
            //
            DestroyWindow( hWnd );

            break;
        }
    case WM_DESTROY:

        //
        // Destroy the application.
        //
        PostQuitMessage( 0 );
        return 0;
    }

    //
    // Handle unhandled messages.
    //

    return DefWindowProc( hWnd, message, wParam, lParam );

}


BOOL
GetTabClientRect( IN HWND hWndTab,
                  IN LPRECT lpRect
                  )
/*++

Routine Description:

  GetTabClientRect calculates the client area of the Tab control relative
  to the main window

Arguments:

  HWND hWndTab -- handle of tab control
  LPRECT lpRect -- pointer to RECT structure that will recieve the data

Return Value:

  BOOL - TRUE if successful

--*/

{
   UINT fSuccess = TRUE;

   // first get the size of the tab control
   if (GetWindowRect( hWndTab, lpRect ) == FALSE)
      fSuccess = FALSE;

   // adjust it to compensate for the tabs
   TabCtrl_AdjustRect( hWndTab, FALSE , lpRect);

   // convert the screen coordinates to client coordinates
   MapWindowPoints( HWND_DESKTOP, GetParent(hWndTab), (LPPOINT) lpRect, 2);

   return(fSuccess);

}


BOOL
MakeTabs(
    IN HWND hWnd,
    IN HWND hMainTabControl
    )
/*++

Routine Description:

    MakeTabs fills out the Main Tab Control with appropriate tabs

Arguments:

    HWND hWnd - handle of main window
    HWND hMainTabControl - handle to the tab control

Return Value:

    BOOL - Returns TRUE if successful.

--*/
{

    DLGHDR *pHdr = (DLGHDR *) LocalAlloc(LPTR, sizeof(DLGHDR));
	DLGHDR *pOldHdr = (DLGHDR *) GetWindowLong( hWnd, GWL_USERDATA );

    TC_ITEM tci;
    TCHAR   pszTabText[30];
	
    int i;

    DWORD Tab[C_PAGES] = {IDD_VERSION_TAB,
                          IDD_HARDWARE_TAB,
                          IDD_VIDEO_TAB,
                          IDD_DRIVES_TAB,
                          IDD_MEMORY_TAB,
                          //IDD_INSTALLATION_TAB,
                          IDD_DRIVERS_SERVICES_TAB,
                          IDD_IRQ_PORT_DMA_MEM_TAB,
                          IDD_ENVIRONMENT_TAB,
                          //IDD_PRINTING_TAB,
                          IDD_NETWORK_TAB
                          };


	//
	// If the old pointer is valid, remove all tabs free 
	// the structure, then save a pointer to the new DLGHDR structure.
	//

	if (pOldHdr)
	{
        
        // Destroy the current child dialog box, if any.
        if (pOldHdr->hwndDisplay != NULL)
        {
            DestroyWindow(pOldHdr->hwndDisplay);
        }

		TabCtrl_DeleteAllItems(hMainTabControl);	

		LocalFree(pOldHdr);

	}

    SetWindowLong(hWnd, GWL_USERDATA, (LONG) pHdr);

	//
	// Save pointers to the tab procs
	//

	pHdr->ChildTabProc[0] = VersionTabProc;
	pHdr->ChildTabProc[1] = HardwareTabProc;
	pHdr->ChildTabProc[2] = VideoTabProc;
	pHdr->ChildTabProc[3] = DrivesTabProc;
    pHdr->ChildTabProc[4] = MemoryTabProc;
	pHdr->ChildTabProc[5] = DevicesAndServicesTabProc;
	pHdr->ChildTabProc[6] = DeviceDlgProc;
	pHdr->ChildTabProc[7] = EnvironmentTabProc;
	pHdr->ChildTabProc[8] = NetworkDlgProc;

	//
	// Save pointers to the print procs
	//

	pHdr->TabPrintProc[0] = BuildOsVerReport;
	pHdr->TabPrintProc[1] = BuildHardwareReport;
	pHdr->TabPrintProc[2] = BuildVideoReport;
	pHdr->TabPrintProc[3] = BuildDrivesReport;
    pHdr->TabPrintProc[4] = BuildMemoryReport;
	pHdr->TabPrintProc[5] = BuildServicesReport;
	pHdr->TabPrintProc[6] = BuildResourceReport;
	pHdr->TabPrintProc[7] = BuildEnvironmentReport;
	pHdr->TabPrintProc[8] = BuildNetworkReport;	

    // Save the handle to the main tab control.
    pHdr->hwndTab = hMainTabControl;

	//
	// Assume we will be displaying the tab
	//									   
	for (i = 0; i < C_PAGES; i++) 
	{
		pHdr->fActiveTab[i] = TRUE;
    }

	// Check to see if the network is running
	// if it is not, do not display the network tab
	if (NERR_WkstaNotStarted == NetWkstaGetInfo( L"", 100L,(LPBYTE *) pszTabText ))
	{
		pHdr->fActiveTab[8] = FALSE;
	}

	// If we are remote, disable the Drives and Memory tabs
	if (_fIsRemote)
	{
		pHdr->fActiveTab[3] = FALSE;
		pHdr->fActiveTab[4] = FALSE;   
	}

	//
	// For the Active tabs, insert them in the control
	//

    tci.mask         = TCIF_TEXT | TCIF_PARAM;
    tci.pszText      = pszTabText;
    tci.cchTextMax   = sizeof( pszTabText );

    for (i = 0; i < C_PAGES; i++) {

		if ( pHdr->fActiveTab[i] )
		{
			// Get the Tab title, the current index + the strind ID
			tci.pszText = (LPTSTR) GetString( i + IDS_FIRST_TAB);

			// store the index to the procs
			tci.lParam = i;

			// insert the tab
			TabCtrl_InsertItem( hMainTabControl, i + 1, &tci );

			// lock the resources for the dialog
			pHdr->apRes[i] = DoLockDlgRes( MAKEINTRESOURCE( Tab[i] ) );	 
		}  

    }

    // Save the size of the tab control's client area
    GetTabClientRect( pHdr->hwndTab , &pHdr->rcDisplay );


    return(TRUE);

}


DLGTEMPLATE * WINAPI
DoLockDlgRes(LPWSTR lpszResName)
/*++

Routine Description:

    DoLockDlgRes - loads and locks a dialog template resource.

Arguments:

    lpszResName - name of the resource

Return Value:

    Returns a pointer to the locked resource.

--*/
{

    HRSRC hrsrc = FindResource(NULL, lpszResName, RT_DIALOG);
    HGLOBAL hglb = LoadResource(_hModule, hrsrc);
    return (DLGTEMPLATE *) LockResource(hglb);

}


BOOL
DoRunApplication( IN HWND hWnd )
/*++

Routine Description:

    DoRunApplication

    Invoke the run application dialog box. Afterwards, execute the command
    that the user entered. [Borrowed from MSINFO32]


Arguments:

    hWnd - handle of main window

Return Value:

    TRUE is successful

--*/
{
    BOOL bOK = FALSE;


     //
     // Call the dialog
     //
     BOOL fRun = DialogBox(_hModule,
                           MAKEINTRESOURCE(IDD_RUN_APPLICATION),
                           hWnd,
                           (DLGPROC) RunDlgProc);

     //
     // Execute the command line
     //
     if (fRun)
         {
         HCURSOR hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
         StartProcess(NULL, g_szRunApp);
         SetCursor(hcurPrev);
         bOK = TRUE;
         }


    return (bOK);
}



LRESULT
RunDlgProc(
    HWND    hDlg,
    UINT    message,
    WPARAM  wParam,
    LPARAM  lParam)
/*++

Routine Description:

    RunDlgProc "Run System Applications" dialog box procedure.

Arguments:

    Standard WNDPROC entry.

Return Value:

    LRESULT - Depending on input message and processing options.

--*/
{
    OPENFILENAME ofn;

    switch (message)
    {
    case WM_INITDIALOG:
        {
        HWND hWndRunList = GetDlgItem(hDlg, didlbxProgs);
        int i;

        //
        //  Initialize applications listbox w/ existing applications
        //

        for (i = 0; i < NumberOfEntries( Tools ); i++){
               ListBox_AddString( hWndRunList, GetString( Tools[i].iDisplayName) );
        }

        //
        //  Set the initial selection to null and disable the OK button
        //

        ListBox_SetCurSel(hWndRunList, -1);
        EnableControl(hDlg, IDOK, FALSE);

        //
        //  Setup the history list
        //

        InitHistoryList(hDlg);
        return(TRUE);

        }

    case WM_COMMAND:
        {
        HWND hWndRunList = GetDlgItem(hDlg, didlbxProgs);
        WORD wID = LOWORD(wParam);
        WORD wNotifyCode = HIWORD(wParam);
        BOOL bValid;

        if ((wID == IDOK) || (wID == IDCANCEL))
            {
            if (wID == IDCANCEL)
                {
                g_szRunApp[0] = UNICODE_NULL;
                }
            else
                {
				    GetRunCommand(hDlg, g_szRunApp, sizeof(g_szRunApp));
                }
            EndDialog(hDlg, (wID == IDOK));
            return(TRUE);
            }

        //  If the run history list is clicked, remove any highlight from run list
        //  and enable OK if command is nonblank
        else if (wID == didcbxRunHistory)
            {
            if ((wNotifyCode == CBN_EDITCHANGE) ||
                (wNotifyCode == CBN_SELCHANGE)  ||
                (wNotifyCode == CBN_SETFOCUS))
                {
                ListBox_SetCurSel(hWndRunList, -1);
                bValid = GetRunHistoryCommand(hDlg, g_szRunApp, sizeof(g_szRunApp));
                EnableControl(hDlg, IDOK, bValid);
                }
            break;
            }

        else if (wID == didbtnBrowse)
            {
            TCHAR szFilters[MAX_PATH];
            TCHAR szTitle[64];
            TCHAR szDir[MAX_PATH];
            TCHAR szPath[MAX_PATH];


            // get filters and fix nulls
            lstrcpy(szFilters, GetString (IDS_PROGRAMFILTERS) );
            FixupNulls(szFilters);

            //get title
            lstrcpy(szTitle, GetString( IDS_BROWSE ) );

            // On NT, we like to start apps in the HOMEPATH directory.  This
            // should be the current directory for the current process.

            GetEnvironmentVariable(TEXT("HOMEDRIVE"), szDir, sizeof(szDir));
            GetEnvironmentVariable(TEXT("HOMEPATH"), szPath, sizeof(szPath));

            lstrcat(szDir, L"\\");
            lstrcat(szDir, szPath);

            // reuse szPath for filename
            szPath[0] = UNICODE_NULL;

             // Setup info for comm dialog.
             ofn.lStructSize       = sizeof(ofn);
             ofn.hwndOwner         = hDlg;
             ofn.hInstance         = NULL;
             ofn.lpstrFilter       = szFilters;
             ofn.lpstrCustomFilter = NULL;
             ofn.nFilterIndex      = 1;
             ofn.nMaxCustFilter    = 0;
             ofn.lpstrFile         = szPath;
             ofn.nMaxFile          = MAX_PATH;
             ofn.lpstrInitialDir   = szDir;
             ofn.lpstrTitle        = szTitle;
             ofn.Flags             = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
             ofn.lpfnHook          = NULL;
             ofn.lpstrDefExt       = NULL;
             ofn.lpstrFileTitle    = NULL;

            // Call it.
            if (GetOpenFileName(&ofn)){

               //if there is a space in the path, quote the string
               if(wcschr(ofn.lpstrFile, L' ')){
                  wsprintf(szDir, L"\"%s\"", ofn.lpstrFile);
                  SetDlgItemText( hDlg, didcbxRunHistory,  szDir);
               }
               else{
                  SetDlgItemText( hDlg, didcbxRunHistory, ofn.lpstrFile);
               }

               EnableControl(hDlg, IDOK, TRUE);
               SetFocus( GetDlgItem( hDlg, IDOK ) );
            }
            return(TRUE);
            }
        else if (wID == didlbxProgs)
            {
            INT nCurSel = ListBox_GetCurSel(hWndRunList);
            BOOL bValidSelection = (nCurSel != LB_ERR);
            if (wNotifyCode == LBN_DBLCLK)
                {
                if (bValidSelection)
                    {
			             GetRunCommand(hDlg, g_szRunApp, lstrlen(g_szRunApp));
		                EndDialog(hDlg, TRUE);
		                return (TRUE);
                    }
                }
            EnableControl(hDlg, IDOK, bValidSelection);
            }
        break;
        }
    }

    return(FALSE);
}



BOOL
GetRunCommand (HWND hDlg,
      LPWSTR pszCommand,
      INT nMaxLen
      )
/*++

Routine Description:

    GetRunCommand Copies the command line for the selected application (to be run)
    into the specified buffer.

--*/

{
	BOOL bOK = TRUE;

    HWND hWndRunList = GetDlgItem(hDlg, didlbxProgs);
    INT nAppPos = ListBox_GetCurSel(hWndRunList);

    if (nAppPos == -1)
        {
        BOOL bValid = GetRunHistoryCommand(hDlg, pszCommand, nMaxLen);
        if (bValid)
            {
            ReviseHistoryList(pszCommand);
            }
        else
            {
            bOK = FALSE;
            pszCommand[0] = UNICODE_NULL;
            }
        }

    else
    {
        TCHAR ExpandedPath[MAX_PATH];

        ExpandEnvironmentStrings(Tools[nAppPos].szExecutableName, ExpandedPath, MAX_PATH);

        lstrcpy(pszCommand, ExpandedPath);
    }

	return (bOK);
}


BOOL
GetRunHistoryCommand (HWND hDlg,
      LPWSTR pszCommand,
      INT nMaxLen
      )
/*++

Routine Description:

    GetRunHistoryCommand -- Gets the current command in the run history list

--*/

{
    HWND hWndRunHistory = GetDlgItem(hDlg, didcbxRunHistory);
    INT nCommandLen = GetDlgItemText(hDlg, didcbxRunHistory, (LPTSTR) pszCommand, nMaxLen);
    LPWSTR pszStart = NULL;
    BOOL bOK = 0;

    if (nCommandLen == 0)
        {
        INT nCurSel = ComboBox_GetCurSel(hWndRunHistory);
        if (nCurSel != CB_ERR)
            {
            nCommandLen = ComboBox_GetLBText(hWndRunHistory, nCurSel, pszCommand);
            DbgAssert((nCommandLen != LB_ERR) && (nCommandLen <= nMaxLen));
            }
        }

    pszStart = pszCommand;

    //BUGBUG: the following line is intended to skip initial spaces, but does not work
    // while( lstrcmp(pszStart++, L" ") == 0 );
    bOK = ((nCommandLen > 0) && (*pszStart != UNICODE_NULL));

    return (bOK);
}

BOOL
InitHistoryList (HWND hDlg)
/*++

Routine Description:

    InitHistoryList -- Initialize the history list for the previous commands exectued

--*/

{
    HWND    hWndRunHistory = GetDlgItem(hDlg, didcbxRunHistory);
    LPTSTR  pszRunHistory = NULL;
    LPWSTR  pszPos = NULL;
    LPWSTR  pszEnd = NULL;
    DWORD   cb;
    BOOL    Success;
    HKEY    hKey;

    // Allocate a buffer for the history list
    cb = MAX_HISTORY * MAX_PATH * sizeof(TCHAR);
    pszRunHistory = (LPTSTR) LocalAlloc(LPTR, cb);

    if( pszRunHistory == NULL )
       return(FALSE);

    //
    // Open the winmsd key in the registry
    //

    Success = RegCreateKeyEx( HKEY_CURRENT_USER,
                              SZ_WINMSD_KEY,
                              0,
                              NULL,
                              REG_OPTION_NON_VOLATILE,
                              KEY_ALL_ACCESS,
                              NULL,
                              &hKey,
                              &cb);

    if(Success != ERROR_SUCCESS){
      LocalFree(pszRunHistory);
       return( FALSE );
    }

    //
    // Read the history value
    //
    cb = LocalSize( pszRunHistory );

    Success = RegQueryValueEx( hKey,
                               (LPWSTR) GetString(IDS_HISTORY),
                               0,
                               NULL,
                               (LPBYTE) pszRunHistory,
                               &cb);

    if(Success != ERROR_SUCCESS){
      LocalFree(pszRunHistory);
       return( FALSE );
    }

    RegCloseKey(hKey);

    pszPos = pszRunHistory;
    pszEnd = pszRunHistory + cb;

    while (*pszPos && (pszPos < pszEnd))
        {
        ComboBox_AddString(hWndRunHistory, pszPos);
        pszPos += 1 + lstrlen(pszPos);
        }

   LocalFree(pszRunHistory);

    return (TRUE);
}


BOOL
ReviseHistoryList (LPWSTR pszCommand)
/*++

Routine Description:

    ReviseHistoryList -- Add the command to the front of the history list,
                         removing any existing occurrence(s).

--*/

{
    LPWSTR  pszNewHistory = NULL;
    DWORD   cbMax = MAX_HISTORY * MAX_PATH * sizeof(TCHAR);
    DWORD   dwDisposition;
    UINT    pos;
    DWORD   cbRemainingBytes;
    BOOL    Success;
    HKEY    hKey;

    // Allocate a buffer for the new history list + 1 MAX_PATH for new command
    pszNewHistory = (LPWSTR) LocalAlloc(LPTR, cbMax + (MAX_PATH * sizeof(TCHAR)));

    // make sure we have a buffer
    if(pszNewHistory == NULL){
       DbgAssert(pszNewHistory);
       return(FALSE);
    }

    // Put the command at the front of the history list, obtained from registry
    lstrcpy(pszNewHistory, pszCommand);

    //set the pos to the next available char
    pos = lstrlen(pszNewHistory) + 1;

    //
    // Open the winmsd key in the registry
    //

    Success = RegCreateKeyEx( HKEY_CURRENT_USER,
                              SZ_WINMSD_KEY,
                              0,
                              NULL,
                              REG_OPTION_NON_VOLATILE,
                              KEY_ALL_ACCESS,
                              NULL,
                              &hKey,
                              &dwDisposition);

    if((Success == ERROR_SUCCESS) && (dwDisposition == REG_OPENED_EXISTING_KEY)){

       //
       // We opened an existing key so read the value for the old run history
       //
       cbRemainingBytes = cbMax - pos;

       Success = RegQueryValueEx( hKey,
                                  GetString(IDS_HISTORY),
                                  0,
                                  NULL,
                                  (LPBYTE) &pszNewHistory[pos],
                                  &cbRemainingBytes);

       if((Success == ERROR_SUCCESS) && cbRemainingBytes){

          // make sure the list is double NULL terminated
          cbMax = cbRemainingBytes + pos;
          pszNewHistory[cbMax + 1] = UNICODE_NULL;
          pszNewHistory[cbMax + 2] = UNICODE_NULL;

          while ((pszNewHistory[pos] != UNICODE_NULL)){

              //Stop if the current element matches the text completely
              if (lstrcmpi(pszNewHistory, &pszNewHistory[pos]) == 0){

                    // move the rest of the string up, and exit the while loop.
                    cbMax -= (lstrlen( &pszNewHistory[pos] ) + 1);
                    MoveMemory(&pszNewHistory[pos],
                               &pszNewHistory[pos + (lstrlen( &pszNewHistory[pos] ) + 1)],
                               cbRemainingBytes);
                    break;
              }
              pos += lstrlen( &pszNewHistory[pos] ) + 1;
              cbRemainingBytes = cbMax - pos;
          }
       }
    }

    //
    // Write the history value back to the registry
    //


    Success = RegSetValueEx( hKey,
                             GetString(IDS_HISTORY),
                             0,
                             REG_MULTI_SZ,
                             (LPBYTE) pszNewHistory,
                             cbMax);

    RegCloseKey(hKey);

    LocalFree(pszNewHistory);

    return (TRUE);
}


BOOL StartProcess (LPWSTR pszApplication, LPWSTR pszParameters)
/*++

Routine Description:

    StartProcess -- Starts the command line specified by pszApplication

--*/

{
    BOOL bOK = TRUE;
    PROCESS_INFORMATION pi;
    STARTUPINFO si;

    memset(&si, 0, sizeof(si));
    si.cb = sizeof(si);

    bOK = CreateProcess(pszApplication,         // module name
                        (LPWSTR)pszParameters,	// command line
                        NULL,	                  // process security attributes
                        NULL, 				      // thread security attributes
                        FALSE, 				      // new process inherits handles
                        NORMAL_PRIORITY_CLASS,  // creation flags
                        NULL, 				      // new environment block
                        NULL, 				      // current directory name
                        &si, 		               // STARTUPINFO
                        &pi);			            // PROCESS_INFORMATION
	if (!bOK)
		{
         // WORKITEM: handle failure with a msg
		}

    return (bOK);
}

VOID
FixupNulls(LPWSTR p)
/*++

Routine Description:

    FixupNulls -- since LoadString() only reads up to a null we have to mark
                  special characters where we want nulls then convert them
                  after loading.

--*/
{
   LPTSTR pT;

   while (*p) {
      if (*p == L'#') {
         pT = p;
         p = CharNext(p);
         *pT = UNICODE_NULL;
      }
      else
         p = CharNext(p);
   }
}

//
//  debug support
// 

#if DBG
#define DEBUG 1
#endif

#ifdef DEBUG

int dprintf(LPCTSTR szFormat, ...)
{
    TCHAR szBuffer[4096];
    TCHAR szPrefix[MAX_PATH];

    va_list  vaList;
    va_start(vaList, szFormat);
    
    wvsprintf(szBuffer, szFormat, vaList);

    wsprintf(szPrefix, L"WinMSD: %s", szBuffer);

    OutputDebugString(szPrefix);

    va_end  (vaList);
    return TRUE;
}

#else

int dprintf(LPCTSTR szFormat, ...)
{
    return FALSE;
}

#endif