Thursday, April 21, 2011

VBS: Shiraz Cleanup

' ----------------------------------------------------------------------------
' "THE BEER-WARE LICENSE" (Revision 42):
' Luke A. Leber wrote this file. As long as you retain this notice in full, you
' can do whatever you want with this stuff. If we meet some day, and you think
' this stuff is worth it, you can buy me a beer in return.
' ----------------------------------------------------------------------------
'    Disclaimer:
'        This software is provided "AS IS" - so I'm not responsible for what's done with it - period.
' ----------------------------------------------------------------------------
'    Warnings:
'    * I'm not sure if the file-system structure is correct, I'm going from what I remember from earlier.
'    * I've never written any windows scripting before this...so some peer reviews would be helpful.
' ----------------------------------------------------------------------------
'    Notes:
'    * This file can be embedded into a server for clients to run over the network (Recommended)
'    * This file can be set to run as a Windows Service
'    * This file can be invoked using CScript.exe
'    * This file is doxygen compliant - yes, 1 click HTML / LaTeX Doc Gen
'    * This file was written under the influence. Coding While Intoxicated
' ----------------------------------------------------------------------------

Option Explicit

'VBS doesn't support static, const, or static const class members
'...so global is the only option left
Const EXIT_SUCCESS = 0
Const EXIT_ENV_VAR_NOT_FOUND = 1
Const EXIT_INSTALL_DIR_NOT_FOUND = 2

class ShirazCleanup

    ' Runs when an instance of the ShirazCleanup class is instantiated
    ' File-System permission checking will take some dirty tricks to do in VBS.
    Public Default Function Init()
        ' TODO: Check for file-system access permissions.
        ' Fail gracefully if the program can't run.
    End Function
    
    '/// Runs the cleanup procedure
    '/**
    ' *    @pre
    ' *        None
    ' *    @post
    ' *        None
    ' *    @return
    ' *        An exit code:<br>
    ' *            0 = Success<br>
    ' *            1 = Shiraz Home Not Found<br>
    ' *            2 = Shiraz Installation Not Found<br>
    ' */
    Public Function doCleanup()
        Dim shirazHome
        shirazHome = findShirazHome()
        if (IsEmpty(shirazHome)) Then
            doCleanup = EXIT_ENV_VAR_NOT_FOUND
            onError("Fatal Error - Shiraz Home could not be found")
            Exit Function
        End If
        if(folderExists(shirazHome & "queue") = False) Then
            doCleanup = EXIT_INSTALL_DIR_NOT_FOUND
            onError("Fatal Error - A Shiraz Installation could not be found")
            Exit Function
        End If
        cleanQueues(shirazHome & "queue")
        doCleanup = EXIT_SUCCESS
    End Function

    '/// Attempts to find the SHIRAZ_HOME environment variable
    '/**
    ' *    @pre
    ' *        None
    ' *    @post
    ' *        None
    ' *    @return
    ' *        The value of the SHIRAZ_HOME environment variable if it exists<br>
    ' *        If SHIRAZ_HOME does not exist and the user clicks cancel, an empty string is returned
    ' */
    Private Function findShirazHome()
        Dim shirazHome
        Do Until(shirazHome <> "")
            shirazHome = getEnvironmentVariable("User", "SHIRAZ_HOME")
            If shirazHome = "" Then
                If onError("Shiraz could not be found. (Is SHIRAZ_HOME set correctly?")_
                <> vbRetry Then
                    findShirazHome = Empty
                    Exit Function
                End If
            End If
        Loop
        findShirazHome = shirazHome
    End Function

    '/// Determines whether a folder exists
    '/**
    ' *    @pre
    ' *        None
    ' *    @post
    ' *        None
    ' *    @param folderName
    ' *        The name of the folder to evaluate
    ' *    @return
    ' *        True if the folder exists, false if not.
    ' */
    Private Function folderExists(ByRef folderName)
        Dim fileSystem
        Set fileSystem = CreateObject("Scripting.FileSystemObject")
        if(fileSystem.FolderExists(folderName)) Then
            folderExists = True
        Else
            folderExists = False
        End If
    End Function
    
    '/// Cleans the queues found in the provided folder
    '/**
    ' *    @pre
    ' *        None
    ' *    @post
    ' *        None
    ' *    @param queues
    ' *        The name of the folder to search for queues in
    ' */
    Private Sub cleanQueues(queues)
        Dim fileSystem, queueSet, queue
        Set fileSystem = CreateObject("Scripting.FileSystemObject")
        Set queueSet = filesystem.GetFolder(queues)
        WScript.Echo "Cleaning " & queueSet.SubFolders.Count & " RIP Queue(s)"
        For Each queue In queueSet.SubFolders
            cleanQueue(queue)
        Next
    End Sub

    '/// Cleans the provided queue
    '/**
    ' *    @pre
    ' *        None
    ' *    @post
    ' *        None
    ' *    @param queue
    ' *        The name of the queue to clean
    ' */    
    Private Sub cleanQueue(queue)
        Dim fileSystem, jobFolderSet, jobFolder
        WScript.Echo "|-Cleaning Queue: " & queue
        Set fileSystem = CreateObject("Scripting.FileSystemObject")
        Set jobFolderSet = fileSystem.GetFolder(queue).SubFolders
        For Each jobFolder In jobFolderSet
            cleanJobFolder(jobFolder)
        Next
    End Sub

    '/// Cleans the jobs found in the provided folder
    '/**
    ' *    @pre
    ' *        None
    ' *    @post
    ' *        None
    ' *    @param jobFolder
    ' *        The name of the folder to search for jobs in
    ' *    @note
    ' *        Only files that have the extension *.sjb or *.txt will be affected
    ' */
    Private Sub cleanJobFolder(jobFolder)
        Dim fileSystem, jobSet, job, extension
        WScript.Echo "|--Cleaning Job Folder: " & jobFolder
        Set fileSystem = CreateObject("Scripting.FileSystemObject")
        Set jobSet = fileSystem.GetFolder(jobFolder).Files
        For Each job In jobSet
            extension = Right(LCase(job), 4)
            If(extension = ".sjb" Or extension = ".txt") Then
                WScript.Echo "|----Deleting Job: " & job
                job.Delete()
            Else
                WScript.Echo "|----Skipping Non-Job " & job
            End If
        Next
    End Sub

    '/// A helper function to display a message box upon error
    '/**
    ' *    @pre
    ' *        None
    ' *    @post
    ' *        None
    ' *    @param errorMessage
    ' *        The message to show in the message box
    ' *    @return
    ' *        The result of the message box (which button the user clicked)
    ' */
    Private Function onError(ByRef errorMessage)
        onError = MsgBox("An error was encountered while running Shiraz doCleanup: "_
        & (Chr(10) + Chr(13)) & errorMessage, vbCritical + vbRetryCancel, "Error")
    End Function
    
    '/// Attempts to retrieve the specified variable from the specified profile
    '/**
    ' *    @pre
    ' *        None
    ' *    @post
    ' *        None
    ' *    @param profile
    ' *        This should be either "System" - or - "User"
    ' *    @param variable
    ' *        This is the name of the environment variable to retrieve
    ' *    @return
    ' *        The value of the specified environment variable if it exists<br>
    ' *        If the specified environment variable does not exist, an empty string is returned
    ' */
    Private Function getEnvironmentVariable(ByRef profile, ByRef variable)
        Dim shell, env
        Set shell = WScript.createObject("WScript.Shell")
        Set env = shell.Environment(profile)
        getEnvironmentVariable = env(variable)
    End Function

End Class

' Give the class a test-drive
' (Uncomment to execute)
'Dim cleaner
' cleaner = new ShirazCleanup
'WScript.Echo "Exit Code: " & cleaner.doCleanup()

Monday, April 18, 2011

C++/CLI: Writing to the Windows Registry

/// Attempts to write values to the registry
/**
  * @warning
  *  This is only an example, NEVER expose the registry like this in your API!
  * @see
  *  http://msdn.microsoft.com/en-us/library/b2hs0tae.aspx
  * @pre
  *  None
  * @post
  *  The registry now contains the subkey CurrentUser/Software/productName
  * @param productName
  *  The name of the subkey to create
  * @param majorVersion
  *  A value to add to the productName subkey
  * @param minorVersion
  *  A value to add to the productName subkey
  * @return
  *  True if the operation completed successfully, false if an exception was encountered
  * @throw
  *  This method will not throw
  */
using namespace System;
static Boolean writeRegistry(String^ productName, Int32 majorVersion, Int32 minorVersion)
{
     using Microsoft::Win32::RegistryValueKind;
     using Microsoft::Win32::RegistryKey;
     using Microsoft::Win32::Registry;
     using System::IO::IOException;
     using System::Security::SecurityException;

     try
     {
          RegistryKey^ currentUser = Registry::CurrentUser;
          RegistryKey^ software = currentUser->OpenSubKey("Software", true);
          RegistryKey^ product = software->CreateSubKey(productName);
          product->SetValue("ProductName", productName, RegistryValueKind::String);
          product->SetValue("MajorVersion", majorVersion, RegistryValueKind::DWord);
          product->SetValue("MinorVersion", minorVersion, RegistryValueKind::DWord);
          product->Close();
          software->Close();
     }
     catch(ArgumentNullException^)
     {
          Console::WriteLine("Error - The product name cannot be empty.");
          return false;
     }
     catch(SecurityException^)
     {
          Console::WriteLine("Error - This user account is not permitted to create or open the registry key(s).");
          return false;
     }
     catch(ObjectDisposedException^)
     {
          Console::WriteLine("Error - A registry key was unexpectedly closed.");
          return false;
     }
     catch(UnauthorizedAccessException^)
     {
          Console::WriteLine("Error - This user account is not permitted to write to the registry key(s).");
          return false;
     }
     catch(IOException^)
     {
          Console::WriteLine("Error - An unexpected error has occurred, this may happen if the nesting level exceeds 510.");
          return false;
     }
     return true;
}

Sunday, April 17, 2011

C++/CLI: std::string to System::String^

/// Copies the contents of a std::string into a managed string
/**
  * @preconditions
  *    None
  * @postconditions
  *    None
  * @param string
  *    The std::string to convert
  * @return
  *    A System::String^ created from the std::string
  * @throw
  *    This method will not throw
  */
static System::String^ toManagedString(const std::string& string)
{
     return gcnew System::String(string.c_str());
}

C++/CLI: System::String^ to std::string

/// Copies the contents of a managed System::String^ into a std::string
/**
 * @preconditions
 *    The provided managed string must be initialized.
 * @postconditions
 *    None
 * @param string
 *    The managed string to convert
 * @return
 *    A std::string created from the managed string
 * @throw
 *    This method will throw a NullReferenceException if the input is null
 */
static std::string toStandardString(System::String^ string)
{
     using System::Runtime::InteropServices::Marshal;
     System::IntPtr pointer = Marshal::StringToHGlobalAnsi(string);
     char* charPointer = reinterpret_cast<char*>(pointer.ToPointer());
     std::string returnString(charPointer, string->Length);
     Marshal::FreeHGlobal(pointer);
     return returnString;
}