Return to ReStart Setup Program Source Code
// RSsetupDlg.cpp : implementation file
//
// Copyright © 1999 - 2000 - 2005 Richard A. Ellingson
// http://www.createwindow.com
// mailto:CreateWindow.com@comcast.net

#include "stdafx.h"
#include "RSsetup.h"
#include
"RSsetupDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
     CAboutDlg();

// Dialog Data
     //{{AFX_DATA(CAboutDlg)
     enum { IDD = IDD_ABOUTBOX };
     //}}AFX_DATA

     // ClassWizard generated virtual function overrides
     //{{AFX_VIRTUAL(CAboutDlg)
     protected:
     virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
     //}}AFX_VIRTUAL

// Implementation
protected:
     //{{AFX_MSG(CAboutDlg)
     //}}AFX_MSG
     DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
     //{{AFX_DATA_INIT(CAboutDlg)
     //}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
     CDialog::DoDataExchange(pDX);
     //{{AFX_DATA_MAP(CAboutDlg)
     //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
     //{{AFX_MSG_MAP(CAboutDlg)
          // No message handlers
     //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRSsetupDlg dialog

CRSsetupDlg::CRSsetupDlg(CWnd* pParent /*=NULL*/)
     : CDialog(CRSsetupDlg::IDD, pParent)
{
     //{{AFX_DATA_INIT(CRSsetupDlg)
     m_csContents = _T("");
     m_nShortcut = 0;
     m_csURL = _T("");
     //}}AFX_DATA_INIT
     // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CRSsetupDlg::DoDataExchange(CDataExchange* pDX)
{
     CDialog::DoDataExchange(pDX);
     //{{AFX_DATA_MAP(CRSsetupDlg)
     DDX_Control(pDX, IDC_ENABLE, m_ctlEnableBtn);
     DDX_Text(pDX, IDC_CONTENTS, m_csContents);
     DDX_Radio(pDX, IDC_RESTART, m_nShortcut);
     DDX_Text(pDX, IDC_URL, m_csURL);
     //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CRSsetupDlg, CDialog)
     //{{AFX_MSG_MAP(CRSsetupDlg)
     ON_WM_SYSCOMMAND()
     ON_WM_DESTROY()
     ON_BN_CLICKED(IDC_ENABLE, OnEnable)
     ON_BN_CLICKED(IDC_CREATE, OnCreate)
     ON_BN_CLICKED(ID_APP_ABOUT, OnAppAbout)
     ON_WM_PAINT()
     ON_WM_QUERYDRAGICON()
     ON_WM_TIMER()
     ON_BN_CLICKED(ID_HELP, OnHelp)
     //}}AFX_MSG_MAP
     ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnToolTipNotify)
     ON_MESSAGE(MYMSG_CHECK_DOSSTART, OnCheckDosStart)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRSsetupDlg message handlers

BOOL CRSsetupDlg::OnInitDialog()
{
     CDialog::OnInitDialog();

     // Add "About..." menu item to system menu.

     // IDM_ABOUTBOX must be in the system command range.
     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
     ASSERT(IDM_ABOUTBOX < 0xF000);

     CMenu* pSysMenu = GetSystemMenu(FALSE);
     if (pSysMenu != NULL)
     {
          CString strAboutMenu;
          strAboutMenu.LoadString(IDS_ABOUTBOX);
          if (!strAboutMenu.IsEmpty())
          {
               pSysMenu->AppendMenu(MF_SEPARATOR);
               pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

               // ******* Begin custom code *******

               // We have a Minimize box on the dialog, but we don't want
               // the Size and Maximize options on the system menu so disable them.
               pSysMenu->EnableMenuItem(SC_SIZE, MF_GRAYED);
               pSysMenu->EnableMenuItem(SC_MAXIMIZE, MF_GRAYED);

               // ******* End custom code *******
          }
     }

     // Set the icon for this dialog. The framework does this automatically
     // when the application's main window is not a dialog
     SetIcon(m_hIcon, TRUE);               // Set big icon
     SetIcon(m_hIcon, FALSE);          // Set small icon
     
     // TODO: Add extra initialization here

// ******* Begin custom code *******

     // We'll supply tool tips, so enable the feature.
     EnableToolTips(TRUE);
     // Set the disable text because we'll use it repeatedly.
     m_csDisable = "@Exit rem - DosStart.bat is disabled for Restart shortcut." + CString(0x0d) + CString(0x0a);
     // Get the text from DosStart.bat.
     Read_DosStart();
     // Set the Create Window URL
     m_csURL = "http://www.createwindow.com";
     // Send what we have to the dialog box.
     UpdateData(SEND);
     // We want to display a message box if we need to modify DosStart.bat right away.
     // Post a message so that the message box doesn't appear until after the dialog.
     PostMessage(MYMSG_CHECK_DOSSTART, 0, 0);

// ******* End custom code *******

     return TRUE; // return TRUE unless you set the focus to a control
}

void CRSsetupDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
     {
          CAboutDlg dlgAbout;
          dlgAbout.DoModal();
     }
     else
     {
          CDialog::OnSysCommand(nID, lParam);
     }
}

void CRSsetupDlg::OnDestroy()
{
     WinHelp(0L, HELP_QUIT);
     CDialog::OnDestroy();
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.

void CRSsetupDlg::OnPaint()
{
     if (IsIconic())
     {
          CPaintDC dc(this); // device context for painting

          SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

          // Center icon in client rectangle
          int cxIcon = GetSystemMetrics(SM_CXICON);
          int cyIcon = GetSystemMetrics(SM_CYICON);
          CRect rect;
          GetClientRect(&rect);
          int x = (rect.Width() - cxIcon + 1) / 2;
          int y = (rect.Height() - cyIcon + 1) / 2;

          // Draw the icon
          dc.DrawIcon(x, y, m_hIcon);
     }
     else
     {
          CDialog::OnPaint();
     }
}

// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CRSsetupDlg::OnQueryDragIcon()
{
     return (HCURSOR) m_hIcon;
}
// Everything above this line is AppWizard generated code
// except for a few lines in OnInitDialog()

// ******* Begin custom code *******

// Handle the Enable/Disable DosStart button
void CRSsetupDlg::OnEnable()
{
     // Go get the DosStart text.
     Read_DosStart();
     // Enable/Disable DosStart.bat depending on the first five characters.
     // Reset the Enable/Disable button caption accordingly.
     if(m_csContents.Left(5) == ("@Exit"))
     {
          Enable_DosStart();
          m_ctlEnableBtn.SetWindowText("&Disable DosStart.bat");
     }
     else
     {
          Disable_DosStart();
          m_ctlEnableBtn.SetWindowText("&Enable DosStart.bat");
     }
     // Make the modification to DosStart.bat.
     Write_DosStart();
}

// Handle the Create button
void CRSsetupDlg::OnCreate()
{
     // Get the value of m_nShortcut from the dialog.
     UpdateData(GET);
     // Create the appropriate shortcut
     // depending on which radio button is selected.
     switch(m_nShortcut)
     {
     case 0:
          Create_ReStart_Shortcut();
          break;
     case 1:
          Create_ReBoot_Shortcut();
          break;
     case 2:
          Create_Shutdown_Shortcut();
     }
}

// Get the Windows directory and append the DosStart.bat filename.
CString CRSsetupDlg::Get_DosStart_Path()
{
     char lpFilename[MAX_PATH];

     GetWindowsDirectory(lpFilename, MAX_PATH);
     return CString(lpFilename) + "\\DosStart.bat";
}

// Handler for Close program messages
void CRSsetupDlg::OnCancel()
{
     // I like to override this function so the dialog
     // doesn't close when the Escape key is pressed.
     if(GetKeyState(VK_ESCAPE) & 128)
          return;
     
     CDialog::OnCancel();
}

// Remove the disable line from DosStart.bat
void CRSsetupDlg::Enable_DosStart()
{
     // Don't bother if DosStart.bat is empty.
     if(m_csContents.IsEmpty())
          return;

     // Create an end on line/return to use repeatedly.
     CString eol(CString(0x0d) + CString(0x0a));

     // Remove all disable lines, in case there are more than one.
     while(m_csContents.Find(m_csDisable) != -1)
          m_csContents = m_csContents.Mid(0, m_csContents.Find(m_csDisable)) +
          m_csContents.Mid(m_csContents.Find(m_csDisable) + m_csDisable.GetLength());
     // Now get rid of any blank lines that might be left over.
     while(m_csContents.Find(eol + eol) != -1)
          m_csContents = m_csContents.Mid(0, m_csContents.Find(eol + eol)) +
          m_csContents.Mid(m_csContents.Find(eol + eol) + 2);
     // We might have nothing but a blank line left
     // so remove the last one.
     if(m_csContents.Left(2) == eol)
          m_csContents = m_csContents.Mid(2);
}

void CRSsetupDlg::Disable_DosStart()
{
     // If DosStart.bat is empty, just add the disable line.
     if(m_csContents.IsEmpty())
          m_csContents = m_csDisable;
     else
     {
          // If DosStart.bat isn't empty, check to see if it's already disabled
          // or add the disable line as the first line.
          if(m_csContents.Left(5) != "@Exit")
               m_csContents = m_csDisable + m_csContents;
     }
}

void CRSsetupDlg::Write_DosStart()
{
     DWORD bytes_written;
     HANDLE hFile = {NULL};

     // Overwrite DosStart.bat if it already exsits.
     hFile = CreateFile(Get_DosStart_Path(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
          NULL, CREATE_ALWAYS,
          FILE_FLAG_SEQUENTIAL_SCAN, NULL);

     // Inform the user if we failed to open and couldn't write.
     if(hFile == INVALID_HANDLE_VALUE)
     {
          MessageBox("Unable to write to the DosStart.bat file.", "ReStart setup");
          return;
     }
     WriteFile(hFile, m_csContents, m_csContents.GetLength(), &bytes_written, NULL);
     // We're done with the file handle so close it.
     CloseHandle(hFile);
     // The write might have failed, so inform the user.
     if(m_csContents.GetLength() != (int)bytes_written)
     {
          MessageBox("Unable to write to the DosStart.bat file.", "ReStart setup");
          return;
     }
     // If all we did was empty DosStart.bat, then display the empty message in the edit box.
     if(m_csContents.IsEmpty())
          m_csContents = "DosStart.bat is empty.";
     // Send the text to the dialog.
     UpdateData(SEND);
}

// Create the ReStart Shortcut.
void CRSsetupDlg::Create_ReStart_Shortcut()
{
     HANDLE hFile = {NULL};
     
     // Overwrite the shortcut on the Desktop if it already exists.
     hFile = CreateFile(Get_Desktop_Path() + "Restart Windows.pif", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
                              NULL, CREATE_ALWAYS, NULL, NULL);

     // Inform the user if we failed to open and couldn't write.
     if(hFile == INVALID_HANDLE_VALUE)
     {
          MessageBox("An error occured while creating the shortcut.", "ReStart setup");
          return;
     }
     DWORD written;
     HRSRC hrbpif;
     HGLOBAL hgbpif;
     // The shortcuts use environment variables and they all work on all machines.
     // Therefore, there's no reason to create them programmatically.
     // Instead, they're stored as binary templates within the program.

     // Get the template and load it into a global buffer.
     hrbpif = FindResource(NULL, "#129", "Template");
     hgbpif = LoadResource(NULL, hrbpif);
     // Write the template into the file.
     WriteFile(hFile, (LPCVOID) hgbpif, 967, &written, NULL);
     // We're done with the file handle so close it.
     // Note that the global buffer is released automatically.
     CloseHandle(hFile);
     // The write might have failed, so inform the user.
     if(written != 967)
     {
          MessageBox("An error occured while creating the shortcut.", "ReStart setup");
          return;
     }
}

// Create the ReBoot Shortcut.
void CRSsetupDlg::Create_ReBoot_Shortcut()
{// Same notes as Create_ReStart_Shortcut()
     HANDLE hFile = {NULL};
     
     hFile = CreateFile(Get_Desktop_Path() + "ReBoot Windows.lnk", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
                              NULL, CREATE_ALWAYS, NULL, NULL);
     if(hFile == INVALID_HANDLE_VALUE)
     {
          MessageBox("An error occured while creating the shortcut.", "ReStart setup");
          return;
     }
     DWORD written;
     HRSRC hrbpif;
     HGLOBAL hgbpif;

     hrbpif = FindResource(NULL, "#130", "Template");
     hgbpif = LoadResource(NULL, hrbpif);
     WriteFile(hFile, (LPCVOID) hgbpif, 1188, &written, NULL);
     CloseHandle(hFile);
     if(written != 1188)
     {
          MessageBox("An error occured while creating the shortcut.", "ReStart setup");
          return;
     }
}

// Create the Shutdown Shortcut.
void CRSsetupDlg::Create_Shutdown_Shortcut()
{// Same notes as Create_ReStart_Shortcut()
     HANDLE hFile = {NULL};
     
     hFile = CreateFile(Get_Desktop_Path() + "ShutDown Windows.lnk", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
                              NULL, CREATE_ALWAYS, NULL, NULL);
     if(hFile == INVALID_HANDLE_VALUE)
     {
          MessageBox("An error occured while creating the shortcut.", "ReStart setup");
          return;
     }
     DWORD written;
     HRSRC hrbpif;
     HGLOBAL hgbpif;

     hrbpif = FindResource(NULL, "#131", "Template");
     hgbpif = LoadResource(NULL, hrbpif);
     WriteFile(hFile, (LPCVOID) hgbpif, 1188, &written, NULL);
     CloseHandle(hFile);
     if(written != 1188)
     {
          MessageBox("An error occured while creating the shortcut.", "ReStart setup");
          return;
     }
}

// Get the directory name for the Desktop
CString CRSsetupDlg::Get_Desktop_Path()
{
     HKEY myKey;
     DWORD data_len;
     BOOL success;
     CString csFileName;

     // The directory name of the Desktop is stored in the registry.
     if(RegOpenKeyEx(HKEY_CURRENT_USER,
          "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders",
               NULL, KEY_QUERY_VALUE, &myKey) != ERROR_SUCCESS)
          return ""; // Return nothing if we failed to find it.

     // Find the length of the string.
     if(success = !RegQueryValueEx(myKey, "Desktop", NULL, NULL, NULL, &data_len))
     {
          // If successful, retrieve the string itself.
          success = !RegQueryValueEx(myKey, "Desktop", NULL, NULL,
                                             (LPBYTE) csFileName.GetBuffer(data_len), &data_len);
          // Clean up the CString after direct buffer access.
          csFileName.ReleaseBuffer();
     }
     // Close the registry key
     RegCloseKey(myKey);
     // Append a backslash and return the path.
     csFileName += "\\";
     return csFileName;
}

// Handle the About button
void CRSsetupDlg::OnAppAbout()
{
     // Display the About box.
     CDialog(IDD_ABOUTBOX).DoModal();
}

// Handle tool tips on mouseover
BOOL CRSsetupDlg::OnToolTipNotify(UINT id, NMHDR *pNMHDR, LRESULT *pResult)
{
     TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
     UINT nID =pNMHDR->idFrom;
     if (pTTT->uFlags & TTF_IDISHWND)
     {
          // idFrom is actually the HWND of the tool
          nID = ::GetDlgCtrlID((HWND)nID);
          if(nID)
          {
               // Get the text from the String Table.
               pTTT->lpszText = MAKEINTRESOURCE(nID);
               pTTT->hinst = AfxGetResourceHandle();
               return TRUE;
          }
     }
     return FALSE;
}

void CRSsetupDlg::Read_DosStart()
{
     DWORD bytes_read, dwFileSize;
     HANDLE hFile = {NULL};

     // Clear our edit box
     m_csContents.Empty();
     // Open DosStart.bat for reading.
     hFile = CreateFile(Get_DosStart_Path(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
          NULL, OPEN_ALWAYS,
          FILE_FLAG_SEQUENTIAL_SCAN, NULL);
     // Inform the user if we failed.
     if(hFile == INVALID_HANDLE_VALUE)
     {
          MessageBox("Unable to read the DosStart.bat file.", "ReStart setup");
          return;
     }
     // Get the file size.
     dwFileSize = GetFileSize(hFile, NULL);
     // If it isn't empty, read it.
     if(dwFileSize)
     {
          // Make buffer big enough to hold the whole thing
          CString buff_data(' ', dwFileSize);
          // Read the file into the buffer.
          ReadFile(hFile, buff_data.GetBuffer(dwFileSize), dwFileSize, &bytes_read, NULL);
          // Put the buffer text in the edit box.
          m_csContents = buff_data;
          // Always release the buffer after writing to it.
          buff_data.ReleaseBuffer();
     }
     // We're done with the file handle so close it.
     CloseHandle(hFile);
     // The read might have failed, so inform the user.
     if(dwFileSize != bytes_read)
     {
          MessageBox("Unable to read the DosStart.bat file.", "ReStart setup");
          return;
     }
}

void CRSsetupDlg::OnCheckDosStart(WPARAM wparam, LPARAM lparam)
{
     // Create a temporary string with the edit box contents
     // so we can work with it.
     CString csTempContents(m_csContents);
     // Create an end on line/return to use repeatedly.
     CString eol(CString(0x0d) + CString(0x0a));
     CString csLine;
     CStringList m_cslDosStartList;

     // Parse the temporary string, dumping each line into a list.
     while(csTempContents.Find(eol) != -1)
     {
          csLine = csTempContents.Mid(0, csTempContents.Find(eol) +2);
          csTempContents = csTempContents.Mid(csTempContents.Find(eol) +2);
          m_cslDosStartList.AddTail(csLine);
     }

     POSITION pos1, pos2;
     BOOL trufal(0);
     BOOL bWrite(0);
     CString csLow_Line;

     // Set the Enable/Disable button caption.
     m_ctlEnableBtn.SetWindowText("&Disable DosStart.bat");
     // Empty the edit box, we'll reconstruct it from the list.
     m_csContents.Empty();
     // Iterate through the list.
     pos1 = m_cslDosStartList.GetHeadPosition();
     while(pos1)
     {
          // Save the current position in case we need to delete it.
          pos2 = pos1;
          // Get the current line and advance the position.
          csLine = m_cslDosStartList.GetNext(pos1);
          // Save a lower case copy so it's easier to search.
          csLow_Line = csLine;
          csLow_Line.MakeLower();
          // Get rid of any preceding spaces.
          csLow_Line.TrimLeft();
          // If it's a blank line, delete it and set our write flag.
          if(csLow_Line == eol)
          {
               bWrite++;
               m_cslDosStartList.RemoveAt(pos2);
          }
          else // Otherwise, if it starts with an exit command...
          if((csLow_Line.Left(5) == "@exit") || (csLow_Line.Left(4) == "exit"))
          {
               // Reset the Enable/Disable button caption.
               m_ctlEnableBtn.SetWindowText("&Enable DosStart.bat");
               // If it's the first line...
               if(pos2 == m_cslDosStartList.GetHeadPosition())
               {
                    // and it's our disable line, save it.
                    if(csLine == m_csDisable)
                         m_csContents += csLine;
                    else // otherwise, delete it.
                         m_cslDosStartList.RemoveAt(pos2);
               }
               else // If it's not the first line...
               {
                    // If we haven't informed the user, display a message
                    // indicating that we'll fix it.
                    if(!trufal)
                         MessageBox("DosStart.bat contains an Exit command, but it's not on the first line.\nClick OK to fix this condition.",
                              "ReStart setup");
                    // Now remove the line and set the write flag.
                    m_cslDosStartList.RemoveAt(pos2);
                    bWrite++;
               }
               // Set a flag so we don't display the message more than once
               // and we know to insert the disable line as the first line.
               trufal++;
          }
          else // If the line doesn't start with an exit command, save it.
               m_csContents += m_cslDosStartList.GetAt(pos2);
     }
     // If we found an exit command and it wasn't our disable line as the first line
     // then insert the disable line as the first line.
     if(trufal)
     {
          if(m_cslDosStartList.GetAt(m_cslDosStartList.GetHeadPosition()) != m_csDisable)
          {
               m_cslDosStartList.AddHead(m_csDisable);
               m_csContents = m_csDisable + m_csContents;
               // Set the write flag.
               bWrite++;
          }
     }
     // If we ended up with an empty DosStart.bat,
     // indicate so in the edit box.
     if(m_csContents.IsEmpty())
     {
          m_csContents = "DosStart.bat is empty.";
          // Send it to the dialog.
          UpdateData(SEND);
     }
     // If we modified DosStart.bat, rewrite it.
     if(bWrite)
          Write_DosStart();
}

// Handle the Help button.
void CRSsetupDlg::OnHelp()
{
     OnHelpFinder();
}
// ******* End custom code *******