The purpose of this application is to monitor extra disk activity, based on the notifications sent by the Windows file system or Shell.
The GUI is the same than with the zTrace utility, using a popup toolwindow (no icon in task bar).
All options could be set from the contextual popup menu, they are:
- "Use horizontal scrollbar"
- "Send selection to printer"
- "Copy selection to clipboard"
- "Clear content"
- "Set window TopMost"
- "Create WatchDog.txt report"
- "Save window coordinates"
'+--------------------------------------------------------------------------+
'| |
'| WatchDog 1.00 |
'| |
'| Monitor notifications from the Windows file system or Shell |
'| |
'+--------------------------------------------------------------------------+
'| |
'| Author Pierre Bellisle & Patrice TERRIER |
'| |
'| http://www.zapsolution.com |
'| |
'+--------------------------------------------------------------------------+
'| Project started on : 11-04-2016 (MM-DD-YYYY) |
'| Last revised : 11-04-2016 (MM-DD-YYYY) |
'+--------------------------------------------------------------------------+
#COMPILE EXE "WatchDog.exe"
#INCLUDE "windows.inc"
#INCLUDE "commdlg.inc"
DECLARE FUNCTION zTrace LIB "zTrace.DLL" ALIAS "zTrace" (zMessage AS ASCIIZ) AS LONG
'----------------------------------------------------------------------
%CSIDL_DESKTOP = &H0000???
%SHCNRF_InterruptLevel = &H0001???
%SHCNRF_ShellLevel = &H0002???
%SHCNRF_RecursiveInterrupt = &H1000???
%SHCNRF_NewDelivery = &H8000???
%SHCNE_RENAMEITEM = &H00000001???
%SHCNE_CREATE = &H00000002???
%SHCNE_DELETE = &H00000004???
%SHCNE_MKDIR = &H00000008???
%SHCNE_RMDIR = &H00000010???
%SHCNE_MEDIAINSERTED = &H00000020???
%SHCNE_MEDIAREMOVED = &H00000040???
%SHCNE_DRIVEREMOVED = &H00000080???
%SHCNE_DRIVEADD = &H00000100???
%SHCNE_NETSHARE = &H00000200???
%SHCNE_NETUNSHARE = &H00000400???
%SHCNE_ATTRIBUTES = &H00000800???
%SHCNE_UPDATEDIR = &H00001000???
%SHCNE_UPDATEITEM = &H00002000???
%SHCNE_SERVERDISCONNECT = &H00004000???
%SHCNE_UPDATEIMAGE = &H00008000???
%SHCNE_DRIVEADDGUI = &H00010000???
%SHCNE_RENAMEFOLDER = &H00020000???
%SHCNE_FREESPACE = &H00040000???
%SHCNE_DISKEVENTS = &H0002381F???
%SHCNE_GLOBALEVENTS = &H0C0581E0???
%SHCNE_ALLEVENTS = &H7FFFFFFF???
%SHCNE_INTERRUPT = &H80000000???
type SHITEMID
cb as word
abID(0) as byte
end type
type ITEMIDLIST
mkid as SHITEMID
end type
type SHChangeNotifyEntry
pidl as ITEMIDLIST ptr
fRecursive as long
end type
$Nil = "Nil"
$SPACE = " "
declare function SHGetPathFromIDList LIB "Shell32.dll" alias "SHGetPathFromIDListA" (byval pidl as ITEMIDLIST ptr, pszPath as asciiz) as long
declare function SHGetSpecialFolderLocation LIB "Shell32.dll" alias "SHGetSpecialFolderLocation" (byval hwnd as dword, byval csidl as long, ppidl as any) as long
declare function SHChangeNotifyRegister LIB "Shell32.dll" alias "SHChangeNotifyRegister" (byval hwnd as dword, byval fSources as long, byval fEvents as long, byval wMsg as dword, byval cEntries as long, pshcne as any) as dword
declare function SHChangeNotifyDeregister LIB "Shell32.dll" alias "SHChangeNotifyDeregister" (byval ulID as dword) as long
%dwStyle = %WS_VISIBLE or %WS_CLIPSIBLINGS or %WS_CLIPCHILDREN or %WS_CAPTION or %WS_SYSMENU or %WS_THICKFRAME
%dwExStyle = %WS_EX_TOOLWINDOW
$WATCHDOG = "WatchDog 1.00"
%BRUSHCOLOR = &HF8D2B0
%HORIZONTAL_EXTENT = 6000 '// Maximum value for the horizontal scrollbar
%MIN_WIDTH = 300 '// default client width size
%MIN_HEIGHT = 104 '// default client height size
%ID_LISTBOX = 1
%IDM_About = 101 '// menu popup
%IDM_Hscroll = 103 '// menu popup
%IDM_Print = 104 '// menu popup
%IDM_CopyToClipboard = 105 '// menu popup
%IDM_ClearContent = 106 '// menu popup
%IDM_TopMost = 107 '// menu popup
%IDM_Report = 108 '// menu popup
%IDM_SaveCoordinates = 109 '// menu popup
type PROP
backbrush as dword
x as long
y as long
w as long
h as long
savecoordinates as long
topmost as long
report as long
usescrollbar as long
end type
global gP as PROP
function FileSize(szFileSpec as asciiz) as dword
local fd as WIN32_FIND_DATA
local nRet, hFind as dword
if (len(szFileSpec)) then
hFind = FindFirstFile(szFileSpec, fd)
if (hFind <> %INVALID_HANDLE_VALUE) then
FindClose(hFind)
nRet = fd.nFileSizeLow
end if
end if
function = nRet
end function
sub zLoadSaveCoordinates (byref x as long, byref y as long, byref w as long, byref h as long, byval RW as long)
local zFileName as asciiz * %MAX_PATH
local hFile, BufferSize, dwBytes as dword
static sWasCoordinates as string
zFileName = Get_TempPath + "WatchDog.cfg"
if (RW) then
sWasCoordinates = ltrim$(str$(x)) + "," + ltrim$(str$(y)) + "," + ltrim$(str$(w)) + "," + ltrim$(str$(h)) + "," + _
ltrim$(str$(gP.topmost)) + "," + _
ltrim$(str$(gP.savecoordinates)) + "," + _
ltrim$(str$(gP.usescrollbar)) + "," + _
ltrim$(str$(gP.report))
hFile = CreateFile(zFilename, %GENERIC_WRITE, 0, byval %NULL, %CREATE_ALWAYS, %FILE_ATTRIBUTE_NORMAL, byval %NULL)
if (hFile <> %INVALID_HANDLE_VALUE) then
WriteFile(hFile, byval strptr(sWasCoordinates), len(sWasCoordinates), dwBytes, byval %NULL)
CloseHandle(hFile)
end if
else
if (len(sWasCoordinates) = 0) then
BufferSize = FileSize(zFilename)
if (BufferSize) then
sWasCoordinates = space$(BufferSize)
hFile = CreateFile(zFilename, %GENERIC_READ, 0, byval %NULL, %OPEN_ALWAYS, %FILE_ATTRIBUTE_NORMAL, byval %NULL)
if (hFile <> %INVALID_HANDLE_VALUE) then
ReadFile(hFile, byval strptr(sWasCoordinates), BufferSize, dwBytes, byval %NULL)
CloseHandle(hFile)
end if
end if
x = val(parse$(sWasCoordinates, 1))
y = val(parse$(sWasCoordinates, 2))
w = val(parse$(sWasCoordinates, 3))
h = val(parse$(sWasCoordinates, 4))
gP.topmost = val(parse$(sWasCoordinates, 5))
gP.savecoordinates = val(parse$(sWasCoordinates, 6)): if (gP.savecoordinates = 0) then w = 0
gP.usescrollbar = val(parse$(sWasCoordinates, 7))
gP.report = val(parse$(sWasCoordinates, 8))
end if
if ((w = 0) or (h = 0)) then w = %MIN_WIDTH: h = %MIN_HEIGHT: x = 0: y = 0
end if
end sub
function List_GetText(byval hList as long, byval nItem as long) as string
local sItem as string, nLen as long
if (nItem > 0) then
decr nItem
nLen = SendMessage(hList, %LB_GETTEXTLEN, nItem, 0)
sItem = space$(nLen)
SendMessage(hList, %LB_GETTEXT, nItem, byval strptr(sItem))
function = sItem
end if
end function
' Get the system temp path
function Get_TempPath () as string
local dwSize as dword, sTempPath as string
sTempPath = space$(GetTempPath(0, byval %NULL))
dwSize = GetTempPath(len(sTempPath), byval strptr(sTempPath))
function = RTRIM$(sTempPath, any CHR$(0,92)) + "\"
end function
' Copy string to a sequential ASCII file.
sub WriteText(zMessage as asciiz)
static NeverBeenThere as long
static hFile as dword
local sBuffer as string
local dwBytesWritten as dword
if ((hFile) and (len(zMessage) = 0)) then
CloseHandle(hFile): hFile = 0
NeverBeenThere = 0
exit sub
end if
if (len(zMessage)) then
if (NeverBeenThere = 0) then
NeverBeenThere = -1
hFile = CreateFile("WatchDog.txt", %GENERIC_WRITE, 0, byval %NULL, %CREATE_ALWAYS, %FILE_ATTRIBUTE_NORMAL, byval %NULL)
end if
if (hFile) then
sBuffer = zMessage + $CRLF
WriteFile(hFile, byval strptr(sBuffer), len(sBuffer), dwBytesWritten, byval %NULL)
end if
end if
end sub
function List_AddString(byval hCtrl as dword, byval zPtr as dword) as long
local nRet as long
if (gP.report) then
if (zPtr) then WriteText(byval zPtr)
end if
nRet = SendMessage(hCtrl, %LB_ADDSTRING, 0, zPtr)
SendMessage(hCtrl, %LB_SETTOPINDEX, nRet, 0)
function = nRet
end function
function ToolProc (byval hWnd as dword, byval Msg as long, byval wParam as long, byval lParam as long) as long
local zPath1 as asciiz * %MAX_PATH
local zPath2 as asciiz * %MAX_PATH
local sMsg as string
local rc, rw as RECT
local K, nCount, nSelItems as long
local sBuffer as string
local hCtrl, hPrinter as dword
local tm as TEXTMETRIC
local di as DOCINFO
local yChar, nLinesPerPage, nCharsPerLine as long
local pd as tagPRINTDLG
select case long (Msg)
case %WM_CREATE:
'// A good place to initiate things, declare variables,
'// create controls and read/set settings from a file, etc.
'-------------------------------------------------------
if (gP.backbrush = 0) then gP.backbrush = CreateSolidBrush(%BRUSHCOLOR)
case %WM_GETMINMAXINFO:
local pMM as MINMAXINFO ptr
SetRect(rc, 0, 0, %MIN_WIDTH, %MIN_HEIGHT)
AdjustWindowRectEx(rc, %dwStyle, %FALSE, %dwExStyle) ' Adjust Window To True Requested Size
pMM = lParam
@pMM.ptMinTrackSize.x = rc.nRight
@pMM.ptMinTrackSize.y = rc.nBottom
case %WM_APP '// SHChangeNotifyRegister/SHCNE_DISKEVENTS notification
'// If %SHCNRF_NewDelivery is not specified, wParam is a pointer
'// to two PIDLIST_ABSOLUTE pointers, and lParam specifies the event.
'// The two PIDLIST_ABSOLUTE pointers can be NULL, depending on the event being sent.
dim p(0 TO 1) as ITEMIDLIST pointer at wParam 'Set an array of two ITEMIDLIST pointers from CBWPARAM
if (p(0)) then
SHGetPathFromIDList(p(0), byval varptr(zPath1))
else
zPath1 = $Nil '// Test if ZERO or a valid pointer
end if
if (p(1)) then
SHGetPathFromIDList(p(1), byval varptr(zPath2))
else
zPath2 = $Nil '// Test if ZERO or a valid pointer
end if
sMsg = ""
select case lParam
case %SHCNE_MEDIAINSERTED : sMsg = "MediaInserted " + zPath1
case %SHCNE_MEDIAREMOVED : sMsg = "MediaRemoved " + zPath1
case %SHCNE_DRIVEREMOVED : sMsg = "DriveRemoved " + zPath1
case %SHCNE_DRIVEADD : sMsg = "DriveAdd " + zPath1
case %SHCNE_RENAMEITEM : sMsg = "RenameItem " + ltrim$(zPath1 + $SPACE + zPath2)
case %SHCNE_CREATE : sMsg = "Create " + ltrim$(zPath1 + $SPACE + zPath2)
case %SHCNE_DELETE : sMsg = "Delete " + ltrim$(zPath1 + $SPACE + zPath2)
case %SHCNE_MKDIR : sMsg = "MakeDir " + ltrim$(zPath1 + $SPACE + zPath2)
case %SHCNE_RMDIR : sMsg = "RemoveDir " + ltrim$(zPath1 + $SPACE + zPath2)
case %SHCNE_UPDATEITEM : sMsg = "UpdateItem " + ltrim$(zPath1 + $SPACE + zPath2)
case %SHCNE_RENAMEFOLDER : sMsg = "RenameFolder " + ltrim$(zPath1 + $SPACE + zPath2)
end select
if (len(sMsg)) then List_AddString(GetDlgItem(hWnd, %ID_LISTBOX), byval strptr(sMsg))
case %WM_COMMAND:
'Messages from controls and menu items are handled here.
'-------------------------------------------------------
select case long lo(word, wParam)
case %IDCANCEL:
if (hi(word, wParam) = %BN_CLICKED) then
SendMessage(hWnd, %WM_CLOSE, 0, 0)
exit function
end if
case %IDM_About:
sBuffer = " WatchDog window" + _
"|| by Pierre Bellisle & Patrice TERRIER" + _
"|| www.zapsolution.com"
replace "|" with $CR in sBuffer
MessageBox(0, (sBuffer), $WATCHDOG, %MB_OK)
case %IDM_Hscroll:
hCtrl = GetDlgItem(hWnd, %ID_LISTBOX)
gP.usescrollbar = NOT gP.usescrollbar
if (gP.usescrollbar) then
ShowScrollBar(hCtrl, %SB_HORZ, %TRUE)
SendMessage(hCtrl, %LB_SETHORIZONTALEXTENT, %HORIZONTAL_EXTENT, 0)
else
SendMessage(hCtrl, %LB_SETHORIZONTALEXTENT, 1, 0)
ShowScrollBar(hCtrl, %SB_HORZ, %FALSE)
end if
UpdateWindow(hCtrl)
case %IDM_Print:
hCtrl = GetDlgItem(hWnd, %ID_LISTBOX)
nCount = SendMessage(hCtrl, %LB_GETCOUNT, 0, 0)
if (nCount > 0) then
pd.lStructSize = sizeof(pd)
'// get rid of PD_RETURNDEFAULT on the line below if you'd like to
'// see the "Printer Settings" dialog!
pd.Flags = %PD_RETURNDEFAULT or %PD_RETURNDC
if (PrintDlg(pd)) then
hPrinter = pd.hDC
GetTextMetrics(pd.hDC, tm)
yChar = tm.tmHeight + tm.tmExternalLeading
nLinesPerPage = GetDeviceCaps(pd.hDC, %VERTRES) / yChar
nCharsPerLine = GetDeviceCaps(pd.hDC, %HORZRES) / tm.tmAveCharWidth
di.cbSize = sizeof(di)
StartDoc(hPrinter, di)
StartPage(hPrinter)
nSelItems = SendMessage(hCtrl, %LB_GETSELCOUNT, 0, 0)
if (nSelItems > 0) then
redim SelItem(nSelItems - 1) as long
nCount = SendMessage(hCtrl, %LB_GETSELITEMS, nSelItems, varptr(SelItem(0)))
for K = 0 TO nSelItems - 1
sBuffer = List_GetText(hCtrl, SelItem(K))
TextOut(pd.hDC, 0, (yChar * K), byval strptr(sBuffer), len(sBuffer))
next
else
for K = 0 TO nCount - 1
sBuffer = List_GetText(hCtrl, K)
TextOut(pd.hDC, 0, (yChar * K), byval strptr(sBuffer), len(sBuffer))
next
end if
EndPage(hPrinter)
EndDoc(hPrinter)
DeleteDC(hPrinter)
end if
end if
case %IDM_CopyToClipboard:
hCtrl = GetDlgItem(hWnd, %ID_LISTBOX)
nCount = SendMessage(hCtrl, %LB_GETCOUNT, 0, 0)
if (nCount > 0) then
sBuffer = ""
nSelItems = SendMessage(hCtrl, %LB_GETSELCOUNT, 0, 0)
if (nSelItems > 0) then
REDIM SelItem(1 TO nSelItems) as long
nCount = SendMessage(hCtrl, %LB_GETSELITEMS, nSelItems&, varptr(SelItem&(1)))
for K = 1 TO nSelItems
sBuffer = sBuffer + List_GetText(hCtrl, SelItem(K)) + $CRLF
next
else
for K = 0 TO nCount - 1
sBuffer = sBuffer + List_GetText(hCtrl, K) + $CRLF
next
end if
local hClipData, hGlob as dword
hClipData = GlobalAlloc(%GMEM_MOVEABLE or %GMEM_DDESHARE, len(sBuffer) + 1)
hGlob = GlobalLock(hClipData)
POKE$ hGlob, sBuffer + CHR$(0)
GlobalUnlock(hClipData)
if (OpenClipboard(0)) then
EmptyClipboard()
SetClipboardData(%CF_TEXT, hClipData)
CloseClipboard()
else
GlobalFree(hClipData)
end if
end if
case %IDM_ClearContent:
SendMessage(GetDlgItem(hWnd, %ID_LISTBOX), %LB_RESETCONTENT, 0, 0)
case %IDM_TopMost:
gP.topmost = NOT gP.topmost
if (gP.topmost) then
SetWindowPos(hWnd, %HWND_TOPMOST, 0, 0, 0, 0, %SWP_NOSIZE or %SWP_NOMOVE or %SWP_SHOWWINDOW)
else
SetWindowPos(hWnd, %HWND_NOTOPMOST, 0, 0, 0, 0, %SWP_NOSIZE or %SWP_NOMOVE or %SWP_SHOWWINDOW)
end if
case %IDM_Report:
gP.report = NOT gP.report
if (gP.report) then
hCtrl = GetDlgItem(hWnd, %ID_LISTBOX)
nCount = SendMessage(hCtrl, %LB_GETCOUNT, 0, 0)
if (nCount > 0) then
for K = 0 TO nCount - 1
WriteText(List_GetText(hCtrl, K))
next
end if
else
WriteText("") '// Close WriteText.txt if already open.
end if
case %IDM_SaveCoordinates:
gP.savecoordinates = NOT gP.savecoordinates
end select
case %WM_CTLCOLORLISTBOX:
'// wParam is handle of control's display context (hDC)
'// lParam is handle of control
'------------------------------------------------------
if (lParam = GetDlgItem(hWnd, %ID_LISTBOX)) then
SetBkColor(wParam, %BRUSHCOLOR)
function = gP.backbrush
exit function
end if
case %WM_RBUTTONDOWN:
local hMenu, nChoice as long, p as POINTAPI
local menuStyle as long
hMenu = CreatePopupMenu()
if (hMenu) then
AppendMenu(hMenu, %MF_STRING, %IDM_About , "About")
AppendMenu(hMenu, %MF_SEPARATOR, 102 , "")
if (gP.usescrollbar) then menuStyle = %MF_STRING or %MF_CHECKED else menuStyle = %MF_STRING
AppendMenu(hMenu, menuStyle, %IDM_Hscroll , "Use horizontal scrollbar")
AppendMenu(hMenu, %MF_STRING, %IDM_Print , "Send selection to printer")
AppendMenu(hMenu, %MF_STRING, %IDM_CopyToClipboard, "Copy selection to clipboard")
AppendMenu(hMenu, %MF_STRING, %IDM_ClearContent , "Clear content")
if (gP.topmost) then menuStyle = %MF_STRING or %MF_CHECKED else menuStyle = %MF_STRING
AppendMenu(hMenu, menuStyle, %IDM_TopMost , "Set window TopMost")
if (gP.report) then menuStyle = %MF_STRING or %MF_CHECKED else menuStyle = %MF_STRING
AppendMenu(hMenu, menuStyle, %IDM_Report, "create WatchDog.txt report")
if (gP.savecoordinates) then menuStyle = %MF_STRING or %MF_CHECKED else menuStyle = %MF_STRING
AppendMenu(hMenu, menuStyle, %IDM_SaveCoordinates, "Save window coordinates")
GetCursorPos(p)
nChoice = TrackPopupMenuEx(hMenu, %TPM_RETURNCMD, p.X, p.Y, hWnd, byval %NULL)
DestroyMenu(hMenu)
if (nChoice) then SendMessage(hWnd, %WM_COMMAND, MAKLNG(nChoice, 0), 0)
end if
case %WM_MOVE:
GetWindowRect(hWnd, rw): gP.x = rw.nLeft: gP.y = rw.nTop
case %WM_SIZE:
if (wParam <> %SIZE_MINIMIZED) then
gP.w = LOWRD(lParam): gP.h = HIWRD(lParam)
MoveWindow(GetDlgItem(hWnd, %ID_LISTBOX), 0, 0, gP.w, gP.h, %TRUE)
UpdateWindow(hWnd)
GetWindowRect(hWnd, rw): gP.x = rw.nLeft: gP.y = rw.nTop
end if
case %WM_DESTROY:
if (gP.backbrush) then
DeleteObject(gP.backbrush): gP.backbrush = 0
zLoadSaveCoordinates (gP.x, gP.y, gP.w, gP.h, 1)
end if
WriteText("")
PostQuitMessage(0)
function = 0: exit function
end select
function = DefWindowProc(hWnd, Msg, wParam, lParam)
end function
function WinMain (byval hInstance as dword, byval hPrevInstance as dword, _
byval lpCmdLine as asciiz ptr, byval nCmdShow as long) as long
local Msg as tagMsg
local IsInitialized as long
local hWnd, hCtrl as dword
local wcx as WndClassEx, szClassName as asciiz * 80
local rc, rw as RECT
szClassName = $WATCHDOG
wcx.cbSize = sizeof(wcx)
IsInitialized = GetClassInfoEx(hInstance, szClassName, wcx)
if (IsInitialized = 0) then
wcx.cbSize = sizeof(wcx)
wcx.style = %CS_HREDRAW or %CS_VREDRAW or %CS_DBLCLKS
wcx.lpfnWndProc = codeptr(ToolProc)
wcx.cbClsExtra = 0
wcx.cbWndExtra = 0
wcx.hInstance = hInstance
wcx.hIcon = 0
wcx.hCursor = LoadCursor(%NULL, byval %IDC_ARROW)
wcx.hbrBackground = %COLOR_BTNSHADOW
wcx.lpszMenuName = %NULL
wcx.lpszClassName = varptr(szClassName)
wcx.hIconSm = wcx.hIcon
if (RegisterClassEx(wcx)) then IsInitialized = %TRUE
end if
if (IsInitialized) then
local UseX, UseY, UseW, UseH as long
zLoadSaveCoordinates (UseX, UseY, UseW, UseH, 0)
SetRect(rc, 0, 0, UseW, UseH)
AdjustWindowRectEx(rc, %dwStyle, %FALSE, %dwExStyle)
hWnd = CreateWindowEx(%dwExStyle, szClassName, szClassName, _
%dwStyle, _
UseX, UseY, _
rc.nRight - rc.nLeft, _ ' Calculate Window Width
rc.nBottom - rc.nTop, _ ' Calculate Window Height
0, 0, hInstance, byval %NULL)
if (hWnd) then
local nSH_OK as long
local ChangeInfo as SHChangeNotifyEntry
local RegID as dword
SHGetSpecialFolderLocation(hWnd, %CSIDL_DESKTOP, ChangeInfo.pidl) 'Get pidl for desktop to monitor all drives
if (ChangeInfo.pidl) then 'pidl was valid
ChangeInfo.fRecursive = %TRUE 'Do sub-folder
'// Ask Windows to send us message at %WM_APP for many events.
local nEvents as long, wMsg as dword
nEvents = %SHCNE_CREATE or %SHCNE_DELETE or %SHCNE_MKDIR or %SHCNE_RENAMEFOLDER or %SHCNE_RENAMEITEM or _
%SHCNE_RMDIR or %SHCNE_DISKEVENTS or %SHCNE_UPDATEITEM or %SHCNE_UPDATEDIR or %SHCNE_DRIVEADD or _
%SHCNE_DRIVEREMOVED or %SHCNE_MEDIAINSERTED or %SHCNE_MEDIAREMOVED or %SHCNE_SERVERDISCONNECT
RegID = SHChangeNotifyRegister(hwnd, %SHCNRF_SHELLLEVEL, nEvents, %WM_APP, 1, byval varptr(ChangeInfo))
if (RegID > 0) then 'SHChangeNotifyRegister successful
nSH_OK = -1
else
MessageBox(0, "SHChangeNotifyRegister error !", $WATCHDOG, %MB_OK)
end if
else
MessageBox(0, "SHGetSpecialFolderLocation error !", $WATCHDOG, %MB_OK)
end if
if (nSH_OK) then
hCtrl = CreateWindowEx(0, "ListBox", byval %NULL, _
%WS_CHILD or %WS_VISIBLE or %WS_VSCROLL or %WS_HSCROLL or %LBS_MULTIPLESEL or _
%LBS_HASSTRINGS or %LBS_NOINTEGRALHEIGHT or %LBS_EXTENDEDSEL or %LBS_DISABLENOSCROLL, _
0, 0, UseW, UseH, _
hWnd, %ID_LISTBOX, hInstance, byval %NULL)
SendMessage(hCtrl, %WM_SETFONT, GetStockObject(%ANSI_FIXED_FONT), 0)
if (gP.usescrollbar) then
SendMessage(hCtrl, %LB_SETHORIZONTALEXTENT, %HORIZONTAL_EXTENT, 0)
ShowScrollBar(hCtrl, %SB_HORZ, %TRUE)
else
ShowScrollBar(hCtrl, %SB_HORZ, %FALSE)
end if
if (gP.topmost) then
SetWindowPos(hWnd, %HWND_TOPMOST, 0, 0, 0, 0, %SWP_NOSIZE or %SWP_NOMOVE or %SWP_SHOWWINDOW)
else
ShowWindow(hWnd, %SW_SHOW)
end if
UpdateWindow(hWnd)
while GetMessage(Msg, %NULL, 0, 0)
'// Easier to detect the right mouse button click on the listBox from the message pump
if ((Msg.hWnd = hCtrl) and (Msg.Message = %WM_RBUTTONDOWN)) then
ToolProc(hWnd, %WM_RBUTTONDOWN, 0, 0)
else
TranslateMessage(Msg)
DispatchMessage(Msg)
end if
wend
SHChangeNotifyDeregister(RegID) '// Clean up on exit
function = msg.wParam
end if
end if
end if
end function
Thank you guys, this is very usefull for me!
Thanks Patrice and Pierre
From a technical discussion point I would like to know if you have any reason for using SHChangeNotifyRegister over ReadDirectoryChangesW?
Ciao - Carlo
Registers a window to receive notifications from the file system or Shell
...
Hey,
For me, both are nice, always depends on what you want.
One thing for sure is that SHChangeNotifyRegister offer more options if you want to customize the code.
ReadDirectoryChangesW function https://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx
SHChangeNotifyRegister function https://msdn.microsoft.com/en-us/library/windows/desktop/bb762120(v=vs.85).aspx
Options:
SHCNE_ALLEVENTS SHCNE_ASSOCCHANGED SHCNE_ATTRIBUTES SHCNE_CREATE SHCNE_DELETE SHCNE_DRIVEADD SHCNE_DRIVEADDGUI
SHCNE_DRIVEREMOVED SHCNE_EXTENDED_EVENT SHCNE_FREESPACE SHCNE_MEDIAINSERTED SHCNE_MEDIAREMOVED SHCNE_MKDIR
SHCNE_NETSHARE SHCNE_NETUNSHARE SHCNE_RENAMEFOLDER SHCNE_RENAMEITEM SHCNE_RMDIR SHCNE_SERVERDISCONNECT SHCNE_UPDATEDIR
SHCNE_UPDATEIMAGE SHCNE_UPDATEITEM SHCNE_DELETE SHCNE_RENAMEITEM SHCNE_DISKEVENTS SHCNE_GLOBALEVENTS SHCNE_INTERRUPT
For those who may be interested here is some piece of code that play with ReadDirectoryChangesW.
Pierre
#COMPILE EXE
#INCLUDE "win32Api.inc"
DECLARE FUNCTION ReadDirectoryChangesW LIB "Kernel32.dll" ALIAS "ReadDirectoryChangesW" _
(BYVAL hDirectory AS DWORD, BYVAL lpBuffer AS DWORD, BYVAL nBufferLength AS DWORD, _
BYVAL bWatchSubtree AS LONG, BYVAL dwNotifyFilter AS DWORD, lpBytesReturned AS DWORD, _
lpOverlapped AS OVERLAPPED, BYVAL lpCompletionRoutine AS DWORD) AS LONG
GLOBAL hDlg AS DWORD
%Edit01 = 101
'__________________________________________________________________________
SUB TextAdd(BYVAL sText AS STRING)
'Move the caret to the end of text.
SendDlgItemMessage(hDlg, %Edit01, %EM_SETSEL, -1, -1)
sText = sText & $CRLF 'Add a CRLF if needed
'Insert the string at caret position.
SendDlgItemMessage(hDlg, %Edit01, %EM_REPLACESEL, %TRUE, BYVAL STRPTR(sText))
END SUB
'______________________________________________________________________________
THREAD FUNCTION GetFolderChangeNotification(BYVAL pFolder AS STRING POINTER) AS LONG
LOCAL pChangeInfo AS FILE_NOTIFY_INFORMATION POINTER
LOCAL sAnsiFileName AS STRING
LOCAL sLog AS STRING
LOCAL hFile AS DWORD
LOCAL pChangeInfoBuffer AS DWORD
LOCAL BufferSize AS DWORD
LOCAL BytesReturnedCount AS DWORD
LOCAL SubFolder AS LONG
hFile = CreateFile(BYVAL pFolder, %FILE_LIST_DIRECTORY, _
%FILE_SHARE_READ OR %FILE_SHARE_WRITE OR %FILE_SHARE_DELETE, _
BYVAL %NULL, %OPEN_EXISTING, %FILE_FLAG_BACKUP_SEMANTICS, %NULL)
IF hFile = %INVALID_HANDLE_VALUE THEN
MessageBox(%HWND_DESKTOP, "CreateFile error!", "ReadDirectoryChangesW", %MB_TOPMOST)
ELSE
BufferSize = 1023
pChangeInfoBuffer = GlobalAlloc(%GMEM_FIXED OR %GMEM_ZEROINIT, BufferSize)
SubFolder = %FALSE
DO 'Wait for a change
ReadDirectoryChangesW(hFile, pChangeInfoBuffer, GlobalSize(pChangeInfoBuffer), SubFolder, _
%FILE_NOTIFY_CHANGE_FILE_NAME OR _
%FILE_NOTIFY_CHANGE_LAST_WRITE OR _
_ %FILE_NOTIFY_CHANGE_DIR_NAME OR _
_ %FILE_NOTIFY_CHANGE_ATTRIBUTES OR _
_ %FILE_NOTIFY_CHANGE_SIZE OR _
_ %FILE_NOTIFY_CHANGE_LAST_ACCESS OR _
_ %FILE_NOTIFY_CHANGE_CREATION OR _
_ %FILE_NOTIFY_CHANGE_SECURITY OR _
0, BytesReturnedCount, BYVAL 0, 0)
IF BytesReturnedCount THEN
sLog = "BytesReturnedCount " & STR$(BytesReturnedCount) & $CRLF & $CRLF
pChangeInfo = pChangeInfoBuffer
DO
sAnsiFileName = NUL$(@pChangeInfo.FileNameLength)
WideCharToMultiByte(%CP_ACP, %NULL, BYVAL pChangeInfo + 12, @pChangeInfo.FileNameLength / 2, _
BYVAL STRPTR(sAnsiFileName), @pChangeInfo.FileNameLength / 2, BYVAL %NULL, BYVAL %NULL)
sAnsiFileName = RTRIM$(sAnsiFileName, $NUL)
sLog = sLog & "NextEntryOffset" & STR$(@pChangeInfo.NextEntryOffset) & $CRLF & _
"Action " & CHOOSE$(@pChangeInfo.Action, _
"%FILE_ACTION_ADDED", "%FILE_ACTION_REMOVED", "%FILE_ACTION_MODIFIED", _
"%FILE_ACTION_RENAMED_OLD_NAME", "%FILE_ACTION_RENAMED_NEW_NAME") & $CRLF & _
"FileNameLength " & STR$(@pChangeInfo.FileNameLength) & $CRLF & _
"FileName " & sAnsiFileName & $CRLF & $CRLF
IF @pChangeInfo.NextEntryOffset = 0 THEN EXIT LOOP
pChangeInfo = pChangeInfo + @pChangeInfo.NextEntryOffset
LOOP
TextAdd(sLog & STRING$(80, 95) & $CRLF)
END IF
LOOP
GlobalFree(pChangeInfoBuffer)
CloseHandle(hFile)
END IF
END FUNCTION
'______________________________________________________________________________
CALLBACK FUNCTION ShowDIALOG1Proc()
LOCAL sFolder AS STRING
LOCAL hThread AS DWORD
SELECT CASE AS LONG CBMSG
CASE %WM_INITDIALOG
sFolder = "C:\Tmp"
TextAdd("Monitoring folder " & sFolder & $CRLF & STRING$(80, 95) & $CRLF)
PostMessage(GetDlgItem(hDlg, %Edit01), %EM_SETSEL, -1, -1)
THREAD CREATE GetFolderChangeNotification(BYVAL STRPTR(sFolder)) TO hThread
THREAD CLOSE hThread TO hThread
CASE %WM_SIZE
IF CBWPARAM <> %SIZE_MINIMIZED THEN
SetWindowPos(GetDlgItem(hDlg, %Edit01), 0, 5, 5, LO(WORD, CBLPARAM) - 10, HI(WORD, CBLPARAM) - 10, %SWP_NOZORDER)
END IF
END SELECT
END FUNCTION
'______________________________________________________________________________
FUNCTION PBMAIN()
LOCAL hIcon AS DWORD
DIALOG NEW %HWND_DESKTOP, "ReadDirectoryChangesW", , , 400, 250, %WS_POPUP OR %WS_BORDER OR _
%WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX OR %WS_CLIPSIBLINGS OR _
%WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR _
%WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
hIcon = ExtractIcon(GetModuleHandle(""), "%SystemRoot%\system32\powrprof.dll", 1)
SetClassLong(hDlg, %GCL_HICON, hIcon)
CONTROL ADD TEXTBOX, hDlg, %Edit01, _
"Create, copy, rename, edit, delete files etc. in folder...", _
5, 5, 940, 225, %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %WS_HSCROLL OR %WS_VSCROLL OR _
%ES_LEFT OR %ES_MULTILINE OR %ES_AUTOHSCROLL OR %ES_AUTOVSCROLL OR %ES_WANTRETURN OR _
%ES_NOHIDESEL, %WS_EX_CLIENTEDGE OR %WS_EX_LEFT OR %WS_EX_RIGHTSCROLLBAR OR %WS_EX_LTRREADING
DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc
DestroyIcon(hIcon)
END FUNCTION
'______________________________________________________________________________
'
QuoteRegisters a window to receive notifications from the file system or Shell
I suspect that this may not work as a service which is why I probably use the ReadDirectoryChangesW
Hey,
Yep, since a service by nature do not include a window and the corespondent callback function,
to use SHChangeNotifyRegister you sure will need some more work.
SHChangeNotifyRegister: Registers a window to receive notifications... ... wMsg: Message to be posted to the window procedure...
Pierre
Added:
You could use RegisterClass, CreateWindow to create a hidden window in
a thread. (Not WS_VISIBLE) or experiment with RegisterServiceCtrlHandlerEx.
The purpose of the WatchDog UI when receiving notifications
was to easily, cut and paste, save, print, what is going on.