Jump to content

Folder watcher doesn't work when folder has more than a few files


Recommended Posts

Using some very ingenious scripts that I found on this forum, I've put together a special-purpose folder watcher that watches a specified folder for printer output files and then either send them to a printer or converts them to a PDF and prints or opens the PDF. The page about this utility is here:

http://www.columbia.edu/~em36/printfileprinter.html

The one serious problem that it has is that it seems not to detect a new file if there are more than two or three files already in the watched folder. I can't figure out what I'm doing wrong, and will be grateful for any help. Here is the relevant part of the script. I've left out the functions that test whether the file is in use or not, and that send the raw data to the printer or create a PDF, etc. I hope there's enough code here to make sense of it, and will be very grateful for any help. Again, the problem is that the script doesn't detect newly-created files in watched folders with more than a very few files already in it.

My totally ignorant guess is that the problem is in the line $iID = _WinAPI_WaitForMultipleObjects(2, $paObj, 0, 0) - but I don't know how to change it and of course I'm only guessing whether it's relevant or not. Many thanks

 

Global $g_ahObj[2]
$g_ahObj[0] = _WinAPI_FindFirstChangeNotification($watchPath, $FILE_NOTIFY_CHANGE_FILE_NAME)
$g_ahObj[1] = _WinAPI_FindFirstChangeNotification($watchPath, $FILE_NOTIFY_CHANGE_DIR_NAME)

If (Not $g_ahObj[0]) Or (Not $g_ahObj[1]) Then
    MsgBox(BitOR($MB_ICONERROR, $MB_SYSTEMMODAL), 'Error', 'Unable to create change notification.')
    Exit
EndIf

Local $tObjs = DllStructCreate('ptr;ptr')
Local $paObj = DllStructGetPtr($tObjs)
For $i = 0 To 1
    DllStructSetData($tObjs, $i + 1, $g_ahObj[$i])
Next

Local $iID
While 1
    Sleep(100)
    $select = 0
    $print = 0
    $format = ""
    Local $tempPDF
    $tempPDF = 0
    $iID = _WinAPI_WaitForMultipleObjects(2, $paObj, 0, 0)
    Switch $iID
        Case 0 ; WAIT_OBJECT_0
            ; ConsoleWrite('A file was created, renamed, or deleted in the directory.' & @CRLF)

            Local $hSearch = FileFindFirstFile($watchPath & "\*")
            Local $sFileName = "", $iResult = 0
            Local $sFilePath = ""
            While 1
                $sFileName = FileFindNextFile($hSearch)
                ; If there is no more file matching the search.
                If @error Then ExitLoop

                $sFilePath = $watchPath & "\" & $sFileName

                Local $fileUsed
                $fileUsed = 0
                $fileUsed = _FileIsUsed($sFilePath)

                If $fileUsed = 1 Then
                    While 1
                        Sleep(100)
                        $fileUsed = _FileIsUsed($sFilePath)
                        If $fileUsed = 0 Then ExitLoop
                    WEnd
                EndIf
                
                If StringInStr($sFileName, "raw") Then
                    If StringInStr($sFileName, "select") Then $select = 1
                    PrintRawFile($sFilePath, $select)
                Else
                    If StringInStr($sFileName, "lg.") Then
                        $pageSize = "legal"
                    ElseIf StringInStr($sFileName, "a4.") Then
                        $pageSize = "a4"
                    ElseIf StringInStr($sFileName, "us.") Then
                        $pageSize = "letter"
                    EndIf

                    $pdfTemp = 0
                    If StringLower(StringLeft($sFileName, 7) = "pdftemp") Then $pdfTemp = 1

                    If StringInStr($sFileName, ".pcl") Then
                        $format = "pcl"
                        $print = 1
                        If StringLeft($sFileName, 6) = "select" Then
                            $select = 1
                            $print = 1
                        ElseIf StringLeft($sFileName, 3) = "pdf" Then
                            $select = 0
                            $print = 0
                        EndIf
                        MakePDF($sFilePath, $format, $print, $select, $pageSize, $pdfTemp)
                    ElseIf StringInStr($sFileName, ".ps") Then
                        $format = "ps"
                        $print = 1
                        If StringLeft($sFileName, 6) = "select" Then
                            $select = 1
                            $print = 1
                        ElseIf StringLeft($sFileName, 3) = "pdf" Then
                            $select = 0
                            $print = 0
                        EndIf
                        MakePDF($sFilePath, $format, $print, $select, $pageSize, $pdfTemp)
                    ElseIf StringInStr($sFileName, ".esc") Then
                        Sleep(200)
                        $format = "epson"
                        $print = 1
                        If StringLeft($sFileName, 6) = "select" Then
                            $select = 1
                            $print = 1
                        ElseIf StringLeft($sFileName, 3) = "pdf" Then
                            $select = 0
                            $print = 0
                        EndIf
                        MakePDF($sFilePath, $format, $print, $select, $pageSize, $pdfTemp)
                    ElseIf StringInStr($sFileName, ".prn") Then
                        $format = GetFileFormat($sFilePath)
                        $print = 1
                        If StringLeft($sFileName, 6) = "select" Then
                            $select = 1
                            $print = 1
                        ElseIf StringLeft($sFileName, 3) = "pdf" Then
                            $select = 0
                            $print = 0
                        EndIf
                        ConsoleWrite("PRN test format: " & $format & @CRLF)
                        MakePDF($sFilePath, $format, $print, $select, $pageSize, $pdfTemp)
                    EndIf
                EndIf

                ; Display the file name.
                ; $iResult = MsgBox(BitOR($MB_SYSTEMMODAL, $MB_OKCANCEL), "", $watchPath & "\" & $sFileName)
;~              RunWait(@ComSpec & " /c notepad.exe " & $watchPath & "\" & $sFileName)
;~              FileDelete($watchPath & "\" & $sFileName)
                If $iResult <> $IDOK Then ExitLoop ; If the user clicks on the cancel/close button.
            WEnd

            ; Close the search handle.
            FileClose($hSearch)


        Case 1 ; WAIT_OBJECT_0 + 1
            ; ConsoleWrite('A directory was created, renamed, or deleted.' & @CRLF)
        Case Else
            ContinueLoop
    EndSwitch
    If Not _WinAPI_FindNextChangeNotification($g_ahObj[$iID]) Then
        MsgBox(BitOR($MB_ICONERROR, $MB_SYSTEMMODAL), 'Error', 'Unexpected error.')
        Exit
    EndIf
WEnd

 

Link to post
Share on other sites
  • Replies 48
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

..ok #AutoIt3Wrapper_AU3Check_Parameters=-q -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6 -w 7 #Au3Stripper_Ignore_Funcs=_Forked_* #include <Fork.au3> #include <MailSlot.au3>; h

@argumentum I started work and found that I had to make one change in Fork.au3: It tries to use the function _MailSlot_Write(), but the actual function in MailSlot.au3 is _MailSlotWrite(). H

Just for the fun of it, a creative alternative : #include <APIFilesConstants.au3> #include <Array.au3> #include <MsgBoxConstants.au3> #include <WinAPIError

1 minute ago, emendelson said:

wonder if there's something else that could fix the existing code

wouldn't. Forking is better for this case. I've tested the example with fast file create in a RAM drive and works well. Working stopping the "file watcher" may will introduce "miss catch" of an event, so, adapt the example to your code. Should be simple.

Link to post
Share on other sites

This is obviously terrific, but it's far beyond my abilities to reduce the example folder watcher to something that will silently watch for a new or renamed file in a folder and then perform an action on that file. Do you know of any scripts based on your code that I can work with? I've been staring at your code, and I'm just not expert enough to figure out how to use it without the GUI...

Apologies for responding to your help with a question!

Edited by emendelson
Link to post
Share on other sites
3 minutes ago, emendelson said:

but it's far beyond my abilities

lol, is not. It can get cumbersome looking at someone else's code.
..you'd have to start the forked watcher by 

$pidFileMon = _Fork_Func('_Forked_ReadDirectoryChanges("' & GUICtrlRead($guiFFM_Path) & '")', Default, '/ErrorStdOut "note to self to see in Task Manager OR extra CmdLine you may need"')

and to stop it, using the PID from $pidFileMon, just ProcessClose($pidFileMon).
( If you wanna make your own idea, run the _Forked_ReadDirectoryChanges($sPath) from another file. )

The fork will send the events via the MailSlot. The events are "*" separated ( as no filename can have that character ), so, StringSplit() each line from the mailslot and that would give that you the data ( or close to it ) of _WinAPI_FindFirstChangeNotification()

If you get used to passing data with an IPC ( inter process communication ) scheme, in this case MailSlots, you'll free your main loop to do the logic you envision, without the hindering that a process ( in this case, watching file/folder changes ) may do ( lock or slow down your main loop ).

Fear not citizen, help has arrived :D 

Link to post
Share on other sites

Or you may want to take a look at this :

#include <APIFilesConstants.au3>
#include <Array.au3>
#include <MsgBoxConstants.au3>
#include <WinAPIError.au3>
#include <WinAPIFiles.au3>
#include <WinAPIMem.au3>

HotKeySet ("{ESC}", _Exit)

Global $g_sPath = "C:\Apps\Temp\", $nBufferLen = 1048576
If Not FileExists($g_sPath) Then Exit MsgBox($MB_SYSTEMMODAL, 'Error', 'Unable to access folder')

Local $hDirectory = _WinAPI_CreateFileEx($g_sPath, $OPEN_EXISTING, $GENERIC_READ+$GENERIC_WRITE, $FILE_SHARE_READ+$FILE_SHARE_WRITE, $FILE_FLAG_BACKUP_SEMANTICS)
If @error Then Exit MsgBox($MB_SYSTEMMODAL, 'Error', 'Unable to get handle')

Local $pBuffer = _WinAPI_CreateBuffer($nBufferLen), $aData
While True
  $aData = _WinAPI_ReadDirectoryChanges($hDirectory, _
    $FILE_NOTIFY_CHANGE_FILE_NAME + _
    $FILE_NOTIFY_CHANGE_DIR_NAME + _
    $FILE_NOTIFY_CHANGE_ATTRIBUTES + _
    $FILE_NOTIFY_CHANGE_SIZE + _
    $FILE_NOTIFY_CHANGE_LAST_WRITE + _
    $FILE_NOTIFY_CHANGE_LAST_ACCESS + _
    $FILE_NOTIFY_CHANGE_CREATION + _
    $FILE_NOTIFY_CHANGE_SECURITY, $pBuffer, $nBufferLen, 1)
  If Not @error Then
    _ArrayDisplay($aData, '_WinAPI_ReadDirectoryChanges')
  Else
    _WinAPI_ShowLastError('', 1)
  EndIf
WEnd

Func _Exit ()
  Exit
EndFunc

I have been using it successfully for quite some times now.  Downside, it is a blocking function.

Edited by Nine
Link to post
Share on other sites

@Nine - I think this gives me exactly what I need; thank you! Questions

1. When you say this is a blocking function, I think that means that it blocks keystrokes to the script while the function is running. But my script is supposed to run completely silently, displaying error messages and prompts to overwrite an existing file, and nothing else. Am I right in thinking that the blocking function won't get in the way?

2. And this is a beginner's question (and I'm embarrassed to be such a beginner that I ask it). I'm trying to use _ArrayExtract to get the filename into a variable, but the best I can do is this (based on someone else's code), which displays the filename in an array but doesn't extract it to a variable.

If some generous person is willing to let me know how to extract that cell to a variable, I'll be very grateful.

For $i = 0 To (UBound($aData) - 1)
            For $j = 0 To 1
                $aData[$i][$j] = $i & $j
            Next
            Local $aExtract = _ArrayExtract($aData, 1, 1, 0, 0)
            _ArrayDisplay($aExtract, "Filename")
Next

 

Link to post
Share on other sites

1- yes you are right if it is to run silently

2- Just do what you want to do in your loop, something like this :

Local $sFileName 
For $i = 1 To $aData[0][0]
  $sFileName = $g_sPath & $aData[$i][0]
  If FileExists ($sFileName) Then
    _PrintThatFile ($sFileName)
    FileDelete ($sFileName)
  EndIf
Next

 

Edited by Nine
added folder path
Link to post
Share on other sites

@Nine - One more question. I've got my script working with your method, and doing exactly what I want it to do - with one exception. My original script used a ToolTip that allowed the user to Exit the script and also to give information on which folder is being watched, etc. As far as I can tell, the ToolTip doesn't work with your file watcher. Is that because it's a blocking function? If so, do you (or anyone) know a way to use a ToolTip with this? It's not crucial that I have a ToolTip, but it's a convenience for other users who will have this script.

Thank you again for this.

Link to post
Share on other sites
11 minutes ago, argumentum said:

...this is the reason for the IPC. Run @Nine's script and send the array via MailSlot to another "main" script, where you can be free to do anything you'd like.

Thank you for this. I was beginning to see that I would need to do this. Does this mean that I'll need two executables, or that it's possible to to have them both in the same script/executable file.

Link to post
Share on other sites

Yes it is because it is a blocking function. But how do you trigger that tooltip ?  You said you want it to be ran silently, but I believe it could be very easy to implement.

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By UEZ
      I'm searching for a way to set an icon for a system menu entry in the console window. I can add / remove entries but I didn't find a way to set an icon for the entry I made.
      Example:
      #AutoIt3Wrapper_Change2CUI=y #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <GuiMenu.au3> #include <WindowsConstants.au3> Global $id_Test = 5000 Global $hConsole = HWnd(DllCall("kernel32.dll", "hwnd", "GetConsoleWindow")[0]) If Not $hConsole Then Exit HotKeySet("{ESC}", "_Exit") Global $hSysmenu = _GUICtrlMenu_GetSystemMenu($hConsole) Global $iCount = _GUICtrlMenu_GetItemCount ($hSysmenu) _GUICtrlMenu_InsertMenuItem($hSysmenu, $iCount, "Test", $id_Test) _GDIPlus_Startup() $hBitmap_GDI = _GDIPlus_BitmapCreateFromMemory(_Test(), True) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hBitmap_GDI = ' & $hBitmap_GDI & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console $hBmp1 = _WinAPI_CreateSolidBitmap($hConsole, 0xFF0000, 16, 16) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hBmp1 = ' & $hBmp1 & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console $hBmp2 = _WinAPI_CreateSolidBitmap($hConsole, 0x00FF00, 16, 16) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $hBmp2 = ' & $hBmp2 & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console ;ConsoleWrite(_GUICtrlMenu_SetItemBmp($hSysmenu, $id_Test, $hBitmap_GDI, False) & @CRLF) ConsoleWrite(_GUICtrlMenu_SetItemBitmaps($hSysmenu, $id_Test, $hBmp1, $hBmp2, False) & ", " & @error & @CRLF) ;_GUICtrlMenu_SetItemBmp($hSysmenu, $id_Test, 8, False) ;set the default close icon _GDIPlus_Shutdown() Do Sleep(1000) Until False Func _Exit() ConsoleWrite("Bye..." & @CRLF) _GUICtrlMenu_DeleteMenu ($hSysmenu, $id_Test, False) _WinAPI_DeleteObject($hBitmap_GDI) _WinAPI_DeleteObject($hBmp1) _WinAPI_DeleteObject($hBmp2) Exit EndFunc ;Code below was generated by: 'File to Base64 String' Code Generator v1.20 Build 2020-06-05 Func _Test($bSaveBinary = False, $sSavePath = @ScriptDir) Local $Test $Test &= 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAA3XAAAN1wFCKJt4AAADKElEQVQ4yz2RT2gcdRTHP7+Z36y7yzZZdvJv22i0rBpiAwnWCMZrUCGIBxEvpQSEHAQhePLkyUKg6Em9iZCcahH0pFYxkIqiIdHKYmPUUHcDmU2TuJnZzc7s/H7PQ5M8ePAu7/M+X56y1hKGYY+IOEDqOI6TzWY1gFIKEcF1XRzHUWmaJnF8bHBy5pfbnz9fb0hBh2F4bm5ubjWKogudTqdVqVT0/Py853kehUKBQqHA2tqaVKtVfenS2P6HH396PDri9D9+cdC/8dkXNW2t9fb29spRFPmtVqtULBaVMYZ8Pk82m8X3farVKjdv3qCn+FbpnFuXfNpQkkwlX33z3RtaKYXW2mqtcV1XtNZks9kzQCaTIeNp4sSh8rAnzSe0HO5bt1arHR51y79pEcEYo05Aylp7OqOUIk0TRp+aYO5Ki3B3VR3s70pictzZGlC5jHW0UgprLVEU4Xke29vbLCwsoLXGcRRxYjk/2MtLz2X4/tvbaO3y9XoPlUe7CI7VAMYYPM+jXC5jrcUYAwipUeSzHhV/k59+bFK5OMytOxco9ezQTQ2A4ujoqDQ+Ph4sLS2JiNiDgwM5PDyQ3SCQ/5ptubv6rsy9XJIfvnxbNv/8W+7d+9deu/aeTE9PB2EYljSAiKje3l7SNCUIAkDQXp77f3zE4uJ1Xnv9KoWRK+zs1DlfHiCXy2OtBcA5AdDpdHBdl4F+n77BEdz2z3zw/iKvvHqVZ194h0wmz0B/Ca094jjmtE4NEBFarRa7jfvkHgqp/rrKxOQzjF6+wtY/u4g9Jo5TfL+EiGCtxVqLFhGUUhhjsNZgrcvqrU948rFhKlNvEkUdtNvBoFEqPVtUSqGUQiulaDabtNttPC/D5t3fqTU0Y5dfpNFogFhEOLsaxzHtdpsgCNT6+rrSSZIwOztrhoeH' $Test &= 'qdfrRmutJp6e4q+tKsbYs3in7+7r65OhoSE9MzNjkiRBt9ttkiRxjTHkcjl3bGxMPYhjSdP0rLvdLt1uF9d1BcDzPHdyclL0yspKuLGxcT0IgkeKxaINgsADXBFxAefEQB4ImNT3/W4Yhk6z2awtLy9H/wPnrsNEnFPl4QAAAABJRU5ErkJggg==' Local $bString = _WinAPI_Base64Decode($Test) If @error Then Return SetError(1, 0, 0) $bString = Binary($bString) If $bSaveBinary Then Local Const $hFile = FileOpen($sSavePath & "\AutoSave_16x16_04.png", 18) If @error Then Return SetError(2, 0, $bString) FileWrite($hFile, $bString) FileClose($hFile) EndIf Return $bString EndFunc ;==>_Test Func _WinAPI_Base64Decode($sB64String) Local $aCrypt = DllCall("Crypt32.dll", "bool", "CryptStringToBinaryA", "str", $sB64String, "dword", 0, "dword", 1, "ptr", 0, "dword*", 0, "ptr", 0, "ptr", 0) If @error Or Not $aCrypt[0] Then Return SetError(1, 0, "") Local $bBuffer = DllStructCreate("byte[" & $aCrypt[5] & "]") $aCrypt = DllCall("Crypt32.dll", "bool", "CryptStringToBinaryA", "str", $sB64String, "dword", 0, "dword", 1, "struct*", $bBuffer, "dword*", $aCrypt[5], "ptr", 0, "ptr", 0) If @error Or Not $aCrypt[0] Then Return SetError(2, 0, "") Return DllStructGetData($bBuffer, 1) EndFunc ;==>_WinAPI_Base64Decode  
      You must compile and run it to see the menu entry in the console window.

       
      Any idea?
    • By UEZ
      Here another approach to check if a script was already started using atoms and semaphores.
       
      Atom:
      #include <MsgBoxConstants.au3> Global $iSingleton = Singleton() If Not $iSingleton Then Exit MsgBox($MB_TOPMOST, "Singleton Test", "Process is already running!") EndIf MsgBox($MB_TOPMOST, "Singleton Test", "Singleton atom initialized: " & $iSingleton) Singleton_Delete($iSingleton) ; #FUNCTION# ==================================================================================================================== ; Name ..........: Singleton ; Description ...: Checks if the script has been started already. ; Syntax ........: Singleton([$sOccurrenceName = @ScriptFullPath]) ; Parameters ....: $sOccurrenceName - [optional] a string value. Default is @ScriptFullPath. ; Return values .: If the function succeeds, the return value is the newly created atom or 0 else error is set and false is returned. ; Author ........: UEZ ; Modified ......: ; Remarks .......: If Singleton finds the atom it will return 0 and the atom token will be set to extended macro. It can be used to get the atom string using _WinAPI_AtomGlobalGetName. ; Related .......: ; Link ..........: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globalfindatomw ; https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globaladdatomw ; Example .......: No ; =============================================================================================================================== Func Singleton($sOccurrenceName = @ScriptFullPath) Local $iFind = _WinAPI_AtomGlobalFind($sOccurrenceName) If @error Then Return SetError(1, 0, False) If $iFind Then Return SetExtended($iFind, 0) Local $iAtom = _WinAPI_AtomGlobalAdd($sOccurrenceName) If @error Then Return SetError(2, 0, False) Return $iAtom EndFunc ;==>Singleton ; #FUNCTION# ==================================================================================================================== ; Name ..........: Singleton_Delete ; Description ...: Deletes the atom generated by the first started script. ; Syntax ........: Singleton_Delete($iAtom) ; Parameters ....: $iAtom - an integer value which was generated by Singleton ; Return values .: True if successful else false. ; Author ........: UEZ ; Modified ......: ; Remarks .......: Don't forget to call Singleton_Delete before first started script ends. ; Related .......: ; Link ..........: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-globaldeleteatom ; Example .......: No ; =============================================================================================================================== Func Singleton_Delete($iAtom) _WinAPI_AtomGlobalDelete($iAtom) If @error Then Return SetError(1, 0, False) Return True EndFunc ;==>Singleton_Delete ;internal functions Func _WinAPI_AtomGlobalFind($sAtomString) Local $aReturn = DllCall("kernel32.dll", "short", "GlobalFindAtomW", "wstr", $sAtomString) If @error Then Return SetError(1, 0, -1) Return $aReturn[0] EndFunc ;==>_WinAPI_AtomGlobalFind Func _WinAPI_AtomGlobalAdd($sAtomString) Local $aReturn = DllCall("kernel32.dll", "short", "GlobalAddAtomW", "wstr", $sAtomString) If @error Then Return SetError(1, 0, -1) Return $aReturn[0] EndFunc ;==>_WinAPI_AtomGlobalAdd Func _WinAPI_AtomGlobalDelete($nAtom) Local $aReturn = DllCall("kernel32.dll", "short", "GlobalDeleteAtom", "short", $nAtom) If @error Then Return SetError(1, 0, -1) Return $aReturn[0] = 0 EndFunc ;==>_WinAPI_AtomGlobalDelete Func _WinAPI_AtomGlobalGetName($nAtom, $iBufferSize = 512) Local $tBufferAtom = DllStructCreate("wchar name[" & $iBufferSize & "]") Local $aReturn = DllCall("kernel32.dll", "uint", "GlobalGetAtomNameW", "short", $nAtom, "struct*", $tBufferAtom, "int", $iBufferSize) If @error Or Not $aReturn[0] Then Return SetError(1, 0, -1) Return $tBufferAtom.name EndFunc ;==>_WinAPI_AtomGlobalGetName  
      Semaphore:
      #include <MsgBoxConstants.au3> #include <WinAPIError.au3> Global $iSingleton = Singleton("&]8h/x87</htFV4-K*&.b.w~") If Not $iSingleton Then Exit MsgBox($MB_TOPMOST, "Singleton Test", "Process is already running!") EndIf MsgBox($MB_TOPMOST, "Singleton Test", "Singleton Semaphore initialized: " & $iSingleton) ; #FUNCTION# ==================================================================================================================== ; Name ..........: Singleton ; Description ...: Checks if the script has been started already. ; Syntax ........: Singleton($sOccurrenceName) ; Parameters ....: $sOccurrenceName - a string value which will be used to create the semaphore handle. ; Return values .: True if Singleton started the first time. False if script was already started ; Author ........: UEZ ; Modified ......: ; Remarks .......: The system closes the handle automatically when the process terminates. The semaphore object is destroyed when its last handle has been closed. ; Related .......: ; Link ..........: https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsemaphorea ; Example .......: No ; =============================================================================================================================== Func Singleton($sOccurrenceName) If StringLen($sOccurrenceName) > 260 Then $sOccurrenceName = StringLeft($sOccurrenceName, 260) Local $aReturn = DllCall("kernel32.dll", "handle", "CreateSemaphoreA", "ptr", Null, "long", 0, "long", 1, "str", $sOccurrenceName) If @error Or Not $aReturn[0] Then Return SetError(1, 0, -1) Return SetExtended($aReturn[0], $aReturn[0] And _WinAPI_GetLastErrorMessage() = "The operation completed successfully.") EndFunc ;==>Singleton  
      Just start the script twice to see if it works.
      The disadvantage of using atoms is that atoms have a memory that means when your app is crashing or you forgot to delete the atom then the atom does still have the $sOccurrenceName saved and thus Singleton will not work if you use the same same value for $sOccurrenceName.
      With semaphore you don't have this issue.
       
      Thanks to jj2007 and SARG.
    • By BlueSkyMemory
      Hello guys! I'm a rookie in AutoIt lol.
      I've tried to looking up in MSDN and the UDFs, but it can only get the GUID of a usual partition and with the GUID to control it. Now I have no ways😥.
      Thanks a lot for your help!
    • By xYuri
      This simple dllcall gives me error 5, access denied,
      Func _WinAPI_VkKeyScan($__key) _WinAPI_SetLastError(0) $res = DllCall('User32.dll', 'SHORT', 'VkKeyScan', 'CHAR', $__key) _xConsole('res: '&$res) $_LastErr = _WinAPI_GetLastError() If $_LastErr <> 0 Then _xConsole('Err: {' & $_LastErr & '}> ' & _WinAPI_GetLastErrorMessage()) Return $res EndFunc Am i doing something wrong?
      Also tried VkKeyScanA and W
      Edit:
      I want to send `:` via PostMessage() WM_KEYDOWN
    • By Sori
      Not going to dump the code down because it's essentially a keylogger.
      <snip>
×
×
  • Create New...