Introduction
This is the third article on the use of some advanced features of the Autoit[1] language for receiving notifications from the Operating System (OS) on writing files and to be able to make a copy of these (possibly encrypted).
The previous articles deal with the use of COM (Component Object Model) objects, the first shows how to grab data from an MSWord document by COM objects for MSWord and send them to an internet application using WinHttpRequest COM object which implements the Ajax protocol; the second besides the COM objects for MSWord uses properties and methods of the COM objects for Power Point.
Steps to Receive Notifications from the File System
(See also the article of Thomas Caudal Shell Notifications in C#)
- Register a message, this should be a
string
unique in the system:
Local $iMsg = _WinAPI_RegisterWindowMessage('CHANGENOTIFY')
- Associates the message with an Autoit function:
GUIRegisterMsg($iMsg, 'WM_CHANGENOTIFY') ; the message is associated to function WM_CHANGENOTIFY
- Registers a window that receive notifications from the file system:
$g_iID = _WinAPI_ShellChangeNotifyRegister($hWnd,$iMsg,$SHCNE_ALLEVENTS,BitOR($SHCNRF_INTERRUPTLEVEL, $SHCNRF_SHELLLEVEL, $SHCNRF_RECURSIVEINTERRUPT), $Path)
The program below is a step to develop the program BackUp
object of this article; I used it to test the operation in the case of several contemporary folders.
#include <APIShellExConstants.au3>
#include <WinAPI.au3>
#include <WinAPIShellEx.au3>
#include <GUIConstantsEx.au3>
Opt(
OnAutoItExitRegister(
Global $hWnd = GUICreate("Try change on folders", 400, 300)
GUISetState(@SW_SHOW, $hWnd)
Global $ID1 = Guard("D:\Condor", 1)
Global $ID2 = Guard("C:\www", 2)
While 1
If GUIGetMsg() = $GUI_EVENT_CLOSE Then ExitLoop
WEnd
Func Guard($path, $indx)
$Message =
Local $iMsg = _WinAPI_RegisterWindowMessage($Message)
GUIRegisterMsg($iMsg,
; local $g_iID = _WinAPI_ShellChangeNotifyRegister_
($hWnd,$iMsg, $SHCNE_ALLEVENTS, BitOR($SHCNRF_INTERRUPTLEVEL, $SHCNRF_SHELLLEVEL, _
$SHCNRF_RECURSIVEINTERRUPT), $Path, true)
Local $g_iID = _WinAPI_ShellChangeNotifyRegister($hWnd, $iMsg, $SHCNE_UPDATEITEM, _
BitOR($SHCNRF_INTERRUPTLEVEL, $SHCNRF_SHELLLEVEL, $SHCNRF_RECURSIVEINTERRUPT), $path)
If @error Then
MsgBox(BitOR($MB_ICONERROR, $MB_SYSTEMMODAL),
Exit
EndIf
Return $g_iID
EndFunc ;==>Guard
Func WM_CHANGENOTIFY($hWnd, $iMsg, $wParam, $lParam)
#forceref $hWnd, $iMsg
Local $sPath = _WinAPI_ShellGetPathFromIDList(DllStructGetData(DllStructCreate
(
If $SHCNE_UPDATEITEM = $lParam Then ConsoleWrite($sPath & " writed" & @CRLF)
EndFunc ;==>WM_CHANGENOTIFY
Func Deregister()
ConsoleWrite("Deregister" & @CRLF)
If $ID1 Then _WinAPI_ShellChangeNotifyDeregister($ID2)
If $ID2 Then _WinAPI_ShellChangeNotifyDeregister($ID2)
EndFunc ;==>Deregister
The Backup Program
As already anticipated in the overlying introduction, the script deals with automatic backup of files when they are modified: a form permits to choose the file(s) to guard, where to backup and a possible encrypt of the copy; this last option is for those who do not trust the storage of their data on the cloud.
Some clarifications on the data and on the operation of the program:
- The buttons of the form are associated with the functions invoked with the pressure of the same
- The data in the form is accessible through a dictionary where the key is the name associated to a control, for example, the name of the backup folder is Folder;
- Finally, every file to watch is stored in a dictionary where the key is
fileName
to backup (with path) and the value is an array containing:
- the origin folder
- the backup file (complete path)
- the possible encryption password
- the handle returned by
_WinAPI_ShellUPDATENOTIFYRegister
- the fileName
When the button Guard
is pressed, the code below is executed:
Func genGuard($data)
Local $sDrive = "", $sDir = "", $sExtension = "", $Path = "", $file = ""
$psw = $data.item("Password")
$fileToGuard = $data.item("File")
Local $aPathSplit = _PathSplit($fileToGuard, $sDrive, $Path, $File, $sExtension)
$destFolder = $data.item("Folder")
if StringRight($destFolder,1) <> "\" then $destFolder = $destFolder & "\"
$Path = $sDrive & $Path
Local $dataFile[] = [$Path,$destFolder,$psw, 0,$File & $sExtension]
if $data.item("runProgram") = "1" Then ShellExecute($data.item("File"),@SW_MAXIMIZE)
if isNewFolder($Path) Then
Local $iMsg = _WinAPI_RegisterWindowMessage(
GUIRegisterMsg($iMsg,
function WM_UPDATENOTIFY
$dataFile[3] = _WinAPI_ShellChangeNotifyRegister($data.item("fg_winhandle"), _
$iMsg, _
$SHCNE_UPDATEITEM, _ ; guard update file system
BitOR($SHCNRF_INTERRUPTLEVEL, $SHCNRF_SHELLLEVEL, $SHCNRF_RECURSIVEINTERRUPT), _
$Path)
If @error Then
MsgBox(BitOR($MB_ICONERROR, $MB_SYSTEMMODAL),
Exit
EndIf
EndIf
ConsoleWrite("Folder " & $path & " guarded" & @CRLF)
$fileDict.Item($fileToGuard) = $dataFile
EndFunc
For every folder to guard must be created a new message by the function _WinAPI_RegisterWindowMessage
, this is achieved by creating a message with a constant part and a variable number: 'UPDATENOTIFY' & $fileDict.count
.
The file can be opened if the Check Box runProgram
is checked by its associated program through the function ShellExecute
.
With the function _WinAPI_ShellChangeNotifyRegister
, the program tells the Operating System (OS) to call the function WM_UPDATENOTIFY
when the event $SHCNE_UPDATEITEM
[2] i.e., an update on the folder $Path
occurs.
When the event occurs, the OS calls the function WM_UPDATENOTIFY
:
Func WM_UPDATENOTIFY($hWnd, $iMsg, $wParam, $lParam)
#forceref $hWnd, $iMsg
Local $sPath = _WinAPI_ShellGetPathFromIDList(DllStructGetData_
(DllStructCreate(
If $sPath Then
if $fileDict.Exists($sPath) Then ; a file has been updated
Local $dataFile = $fileDict.Item($sPath)
If $dataFile[2] = "" Then ; there is a password?
FileCopy($sPath,$dataFile[1], $FC_OVERWRITE + $FC_CREATEPATH)
Else
_Crypt_EncryptFile($sPath, $dataFile[1] & $dataFile[4], _
$dataFile[2],$CALG_AES_192) ; Encrypt the file.
If @error <> 0 Then
consoleWrite("Error when encrypting: " & @error & @CRLF)
EndIf
EndIf
consoleWrite($sPath & " saved")
if $dataFile[2] <> "" Then ConsoleWrite(" and encrypted")
ConsoleWrite(@CRLF)
EndIf
EndIf
EndFunc ;==>WM_UPDATENOTIFY
If the event is related to a file under control, this is copied to the backup folder or it is copied encrypted[3] if there is a keyword.
Other Features of the Program
I added a subform to recover the encrypted files and in the menu, under File
, the sub menu Show guarded
which shows the files currently under control:
...
& "BL,Restore,Restore,,,Restore the file,Restore;" _
& "Menu,File,&File;" _
& "SubMenu,Showguard,&Show guarded,Showguard;" _
...
Func showGuard()
$aDict = getIniFormat($fileDict)
Local $iOrgWidth = 500, $iHeight = 300
Local $hGUI = GUICreate("Files on guard", $iOrgWidth, $iHeight)
Local $aiGUISize = WinGetClientSize($hGUI)
Local $idListview = GUICtrlCreateListView(StringFormat_
("File %40s |Folder %40s |Encript key","",""), 10, 10, 480, 240)
For $i=1 to $aDict[0][0]
$a = $aDict[$i][1]
Local $idItem = GUICtrlCreateListViewItem_
($aDict[$i][0] & "|" & $a[1] & "|" & $a[2],$idListview)
Next
GUISetState(@SW_SHOW, $hGUI)
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE
ExitLoop
EndSwitch
WEnd
GUIDelete()
EndFunc
Func Restore($data)
$psw = $data.item("PasswordR")
$fileToRestore = $data.item("FileR")
Local $sDrive = "", $sDir = "", $sExtension = "", $Pth = "", $file
Local $aPathSplit = _PathSplit($fileToRestore, $sDrive, $Pth, $File, $sExtension)
$File = $File & $sExtension
$destFile = $data.item("FolderR")
if StringRight($destFile,1) <> "\" then $destFile = $destFile & "\"
$destFile = $destFile & $File
if $psw = "" Then
FileCopy($fileToRestore,$destFile, $FC_OVERWRITE + $FC_CREATEPATH)
Else
_Crypt_DecryptFile($fileToRestore, $destFile, $psw,$CALG_AES_192) ; Decrypt the file.
EndIf
msgbox(0,"Restore",$fileToRestore,1.5)
ConsoleWrite("Restored file " & $fileToRestore & " from " & $Pth & @CRLF)
EndFunc
Notes
- ^AutoIt is a free-ware BASIC-like scripting language, an alternative to PowerShell, designed in origin for automating the interaction with Windows GUI. AutoIt can run on Windows interpreted or compiled. It comes with many libraries that enable, among other things, access COM objects and create graphical interfaces; those task are greatly enhanced by the rich Help with examples.
- ^In the documentation we can find a list of all events, in particular
$SHCNE_ALLEVENTS
matches all events. - ^I used the AES (192bit) algorithm but AutoIt supports some others that can be found in the documentation.
Computer literacy (software) : Languages: PHP, Javascript, SQL Autoit,Basic4Android; Frameworks: JOOMLA!
Teaching/Training skills on Office, WEB site development and programming languages.
Others : WEB site development.
UNDP Missions
feb – may 2003 Congo DR Bukavu: ground IT computer course
nov 2003 Burundi Bujumbura: Oracle Data Base course
feb 2005 Burundi Bujumbura: JAVA course
mar 2005 Mali Kati: MS Office course
oct 2006 Mali Kati: MS Office course
jun 2006 Burkina Faso Bobo Dioulasso: MS Office course
jun 2007 Burkina Faso Bobo Dioulasso: MS Office course
may 2007 Argentina Olavarria hospital: Internet application for access to medical records
apr 2008 Burkina Faso Ouagadougou: MS ACCESS and dynamic Internet applications
jun 2008 Niger Niamey: analysis of the computing needs of the Niamey hospital
may 2009 Burkina Faso Ouagadougou: MS ACCESS and dynamic Internet applications
oct 2010 Niger Niamey: analysis of the computing needs of the Niamey hospital (following)
Region Piedmont project Evaluation
mar 2006 Burkina Faso, Niger
mar 2007 Benin, Burkina Faso, Niger
sep 2008 Benin, Burkina Faso, Niger
Others
feb 2010 Burundi Kiremba hospital: MS Office course
feb 2011 Congo DR Kampene hospital: MS Office course