Jump to content

toasterking

Active Members
  • Posts

    43
  • Joined

  • Last visited

Recent Profile Visitors

930 profile views

toasterking's Achievements

  1. Many thanks from the future, nearly 19 years later! I just used this in a project to schedule outdoor lighting via X10. (Yeah, X10 is ancient but still useful. And yeah, X10 already has software that does this based on sunrise/sunset, but mine (and your) software seems much more reliable. 🙂)
  2. Extremely helpful for a project I was working on at work. No one will ever look at my code again, but you're credited. Thanks!
  3. Thanks, this saved me a lot of work! Some minor changes here: Added command line options. Syntax examples: RegEveryUser.exe add "Software\Policies\Example" "My test value" REG_DWORD 2 RegEveryUser.exe delete "Software\Policies\Example" "My test value" RegEveryUser.exe delete "Software\Policies\Example" Also writes changes to the default user profile so changes will be applied to newly created user profiles. Retries unloading the hive up to 20 times over ~4 seconds if doing so fails. Incorporated thecharliec's SetPrivilege fix. Tidied code and added local variable declarations that were missing. Active Setup, which I consider a cleaner approach, is actually my preferred method for making registry changes or executing any commands once for every user. But in this case, I needed to make a change to a "Policies" key normally written by Group Policy in the absence of a proper GPO implementation. Per-user policy settings are applied by Group Policy by setting a registry value in the "Policies" of the user hive, but the permissions on this subkey are set such that the user cannot write there themselves unless they are a local administrator. In this case, this script is useful to run as a local Administrator to preset the value for every user. #NoTrayIcon #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Outfile=RegEveryUser.exe #AutoIt3Wrapper_Change2CUI=y #AutoIt3Wrapper_Res_Description=Multiple user registry hive updater #AutoIt3Wrapper_Res_Fileversion=1.0.0.100 #AutoIt3Wrapper_Res_Fileversion_AutoIncrement=y #AutoIt3Wrapper_Res_LegalCopyright=toasterking #AutoIt3Wrapper_Res_Language=1033 #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** ;~ #AutoIt3Wrapper_Res_ProductVersion=1.0.0.0 #cs ---------------------------------------------------------------------------- AutoIt Version: 3.3.14.2 Author: Sean Hart Mods: thecharliec, toasterking Script Function: Command-line utility to write or delete registry keys from all user profiles on the system. Active Setup is more efficient unless the user doesn't have permission to manipulate a part of the registry in their own user profile. This is the case with anything in HKCU\Sofware\Policies. Uses _RegLoadHive functions provided by Larry #ce ---------------------------------------------------------------------------- #Region --- Include files #include <WinAPIShellEx.au3> #EndRegion --- Include files Opt("MustDeclareVars", 1) ; Because I'm paranoid. If $CmdLine[0] < 2 Then Exit 1 Switch $CmdLine[1] Case 'add' If $CmdLine[0] < 5 Then Exit 1 _RegWriteAllUsers($CmdLine[2],$CmdLine[3],$CmdLine[4],$CmdLine[5]) Case 'delete' If $CmdLine[0] = 2 Then ;Key only _RegDeleteAllUsers($CmdLine[2],"ÿ") ElseIf $CmdLine[0] >= 3 Then ;Key and value _RegDeleteAllUsers($CmdLine[2],$CmdLine[3]) Else Exit 1 EndIf EndSwitch Exit 0 ; === _RegWriteAllUsers === ; Writes "current user" registry data to every user profile on the system. ; Requires _RegLoadHive and _RegUnloadHive functions. ; ; Inputs: $key - see RegWrite function for details (no HKU\HKCU\HKLM required) ; $value - see RegWrite function for details ; $type - see RegWrite function for details ; $data - see RegWrite function for details ; ; Returns: nothing Func _RegWriteAllUsers($key, $value, $type, $data) Local $i, $curkey, $ExpandEnvStrings, $profiledir, $curdir, $search ; init variables $i = 1 Local $error = 0 $ExpandEnvStrings = Opt("ExpandEnvStrings", 1) $profiledir = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList", "ProfilesDirectory") ; change directory to profile directory $curdir = @WorkingDir FileChangeDir($profiledir) ; replace HKU / HKCU / HKLM in key if require Select Case StringLeft($key, 4) = "HKU\" $key = StringRight($key, StringLen($key) - 4) Case StringLeft($key, 5) = "HKCU\" $key = StringRight($key, StringLen($key) - 5) Case StringLeft($key, 5) = "HKLM\" $key = StringRight($key, StringLen($key) - 5) Case StringLeft($key, 11) = "HKEY_USERS\" $key = StringRight($key, StringLen($key) - 11) Case StringLeft($key, 18) = "HKEY_CURRENT_USER\" $key = StringRight($key, StringLen($key) - 18) Case StringLeft($key, 19) = "HKEY_LOCAL_MACHINE\" $key = StringRight($key, StringLen($key) - 19) EndSelect ; Go through all directories where ntuser.dat is accessible $search = FileFindFirstFile("*.*") Local $dir For $x = 99 To 0 Step -1 $dir = FileFindNextFile($search) If @error Then ;TK: If no more profile directories to process $dir = _WinAPI_GetDefaultUserProfileDirectory() ;TK: Update the default user profile for the last loop. $x = 0 ;TK: Make this the last loop EndIf ; Process directories If StringInStr(FileGetAttrib($profiledir & "\" & $dir), "D") Then ; Check for ntuser.dat If FileExists($profiledir & "\" & $dir & "\ntuser.dat") Then ; Try and load hive If _RegLoadHive("TempUser", $profiledir & "\" & $dir & "\ntuser.dat") Then ; Apply new registry data RegWrite("HKEY_USERS\TempUser\" & $key, $value, $type, $data) ; Unload hive For $z = 1 To 20 If _RegUnloadHive("TempUser") Then ExitLoop Sleep(200) Next EndIf EndIf EndIf Next ; Start by going through all currently logged on user keys (exclude system accounts and classes) $curkey = RegEnumKey("HKEY_USERS", $i) While @error = 0 If (StringLen($curkey) > 8) And (Not StringInStr($curkey, "_Classes")) Then RegWrite("HKEY_USERS\" & $curkey & "\" & $key, $value, $type, $data) EndIf $i = $i + 1 $curkey = RegEnumKey("HKEY_USERS", $i) WEnd ; Put settings back and change back to previous directory Opt("ExpandEnvStrings", $ExpandEnvStrings) FileChangeDir($curdir) EndFunc ;==>_RegWriteAllUsers ; === END _RegWriteAllUsers === ; === _RegDeleteAllUsers === ; Deletes "current user" registry data from every user profile on the system. ; Requires _RegLoadHive and _RegUnloadHive functions. ; ; Inputs: $key - see RegDelete function for details (no HKU\HKCU\HKLM required) ; $value - (optional) see RegDelete function for details ; ; Returns: nothing Func _RegDeleteAllUsers($key, $value = "ÿ") Local $i, $curkey, $ExpandEnvStrings, $profiledir, $curdir, $search ; init variables $i = 1 Local $error = 0 $ExpandEnvStrings = Opt("ExpandEnvStrings", 1) $profiledir = RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList", "ProfilesDirectory") ; change directory to profile directory $curdir = @WorkingDir FileChangeDir($profiledir) ; replace HKU / HKCU / HKLM in key if require Select Case StringLeft($key, 4) = "HKU\" $key = StringRight($key, StringLen($key) - 4) Case StringLeft($key, 5) = "HKCU\" $key = StringRight($key, StringLen($key) - 5) Case StringLeft($key, 5) = "HKLM\" $key = StringRight($key, StringLen($key) - 5) Case StringLeft($key, 11) = "HKEY_USERS\" $key = StringRight($key, StringLen($key) - 11) Case StringLeft($key, 18) = "HKEY_CURRENT_USER\" $key = StringRight($key, StringLen($key) - 18) Case StringLeft($key, 19) = "HKEY_LOCAL_MACHINE\" $key = StringRight($key, StringLen($key) - 19) EndSelect ; Go through all directories where ntuser.dat is accessible $search = FileFindFirstFile("*.*") Local $dir For $x = 99 To 0 Step -1 $dir = FileFindNextFile($search) If @error Then ;TK: If no more profile directories to process $dir = _WinAPI_GetDefaultUserProfileDirectory() ;TK: Update the default user profile for the last loop. $x = 0 ;TK: Make this the last loop EndIf ; Process directories If StringInStr(FileGetAttrib($profiledir & "\" & $dir), "D") Then ; Check for ntuser.dat If FileExists($profiledir & "\" & $dir & "\ntuser.dat") Then ; Try and load hive If _RegLoadHive("TempUser", $profiledir & "\" & $dir & "\ntuser.dat") Then ; Delete registry data If $value = "ÿ" Then RegDelete("HKEY_USERS\TempUser\" & $key) Else RegDelete("HKEY_USERS\TempUser\" & $key, $value) EndIf ; Unload hive For $z = 1 To 20 If _RegUnloadHive("TempUser") Then ExitLoop Sleep(200) Next EndIf EndIf EndIf Next ; Start by going through all currently logged on user keys (exclude system accounts and classes) $curkey = RegEnumKey("HKEY_USERS", $i) While @error = 0 If (StringLen($curkey) > 8) And (Not StringInStr($curkey, "_Classes")) Then ; Delete registry data If $value = "ÿ" Then RegDelete("HKEY_USERS\" & $curkey & "\" & $key) Else RegDelete("HKEY_USERS\" & $curkey & "\" & $key, $value) EndIf EndIf $i = $i + 1 $curkey = RegEnumKey("HKEY_USERS", $i) WEnd EndFunc ;==>_RegDeleteAllUsers ; === END _RegDeleteAllUsers === ; === _RegLoadHive === ; Loads a ntuser.dat file as a registry hive ; Requires SetPrivilege function. ; ; Inputs: $hiveName - name for the hive ; $NTUSER_datFile - full path to ntuser.dat file to load ; $RLH_key - (optional) root for hive (defaults to HKU) ; ; Returns: 1 - Successful ; 0 - Error (sets @error) Func _RegLoadHive($hiveName, $NTUSER_datFile, $RLH_key = "HKU") If Not (@OSType == "WIN32_NT") Then SetError(-1) Return 0 EndIf Const $HKEY_LOCAL_MACHINE = 0x80000002 Const $HKEY_USERS = 0x80000003 Const $SE_RESTORE_NAME = "SeRestorePrivilege" Const $SE_BACKUP_NAME = "SeBackupPrivilege" Local $RLH_ret Local $aPriv[2] If $RLH_key = "HKLM" Then $RLH_key = $HKEY_LOCAL_MACHINE ElseIf $RLH_key = "HKU" Then $RLH_key = $HKEY_USERS Else SetError(-2) Return 0 EndIf $aPriv[0] = $SE_RESTORE_NAME $aPriv[1] = $SE_BACKUP_NAME SetPrivilege($aPriv, 1) $RLH_ret = DllCall("Advapi32.dll", "int", "RegLoadKey", "int", $RLH_key, "str", $hiveName, "str", $NTUSER_datFile) SetError($RLH_ret[0]) Return Not $RLH_ret[0] EndFunc ;==>_RegLoadHive ; === END _RegLoadHive === ; === _RegUnloadHive === ; Unloads a registry hive ; Requires SetPrivilege function. ; ; Inputs: $hiveName - name for the hive ; $RLH_key - (optional) root for hive (defaults to HKU) ; ; Returns: 1 - Successful ; 0 - Error (sets @error) Func _RegUnloadHive($hiveName, $RUH_key = "HKU") If Not (@OSType == "WIN32_NT") Then SetError(-1) Return 0 EndIf Const $HKEY_LOCAL_MACHINE = 0x80000002 Const $HKEY_USERS = 0x80000003 Local $RUH_ret If $RUH_key = "HKLM" Then $RUH_key = $HKEY_LOCAL_MACHINE ElseIf $RUH_key = "HKU" Then $RUH_key = $HKEY_USERS Else SetError(-2) Return 0 EndIf $RUH_ret = DllCall("Advapi32.dll", "int", "RegUnLoadKey", "int", $RUH_key, "Str", $hiveName) Return Not $RUH_ret[0] EndFunc ;==>_RegUnloadHive ; === _RegUnloadHive === ; === SetPrivilege === ; Special function for use with registry hive functions Func SetPrivilege($privilege, $bEnable) Const $TOKEN_ADJUST_PRIVILEGES = 0x0020 Const $TOKEN_QUERY = 0x0008 Const $SE_PRIVILEGE_ENABLED = 0x0002 Local $hToken, $SP_auxret, $SP_ret, $hCurrProcess, $nTokens, $nTokenIndex, $priv, $LUID, $TOKEN_PRIVILEGES, $NEWTOKEN_PRIVILEGES, $ret, $f $nTokens = 1 $LUID = DllStructCreate("dword;int") If IsArray($privilege) Then $nTokens = UBound($privilege) $TOKEN_PRIVILEGES = DllStructCreate("dword;dword[" & (3 * $nTokens) & "]") $NEWTOKEN_PRIVILEGES = DllStructCreate("dword;dword[" & (3 * $nTokens) & "]") $hCurrProcess = DllCall("kernel32.dll", "hwnd", "GetCurrentProcess") $SP_auxret = DllCall("advapi32.dll", "int", "OpenProcessToken", "hwnd", $hCurrProcess[0], "int", BitOR($TOKEN_ADJUST_PRIVILEGES, $TOKEN_QUERY), "int*", 0) If $SP_auxret[0] Then $hToken = $SP_auxret[3] DllStructSetData($TOKEN_PRIVILEGES, 1, 1) $nTokenIndex = 1 While $nTokenIndex <= $nTokens If IsArray($privilege) Then $priv = $privilege[$nTokenIndex - 1] Else $priv = $privilege EndIf $ret = DllCall("advapi32.dll", "int", "LookupPrivilegeValue", "str", "", "str", $priv, _ "ptr", DllStructGetPtr($LUID)) If $ret[0] Then If $bEnable Then DllStructSetData($TOKEN_PRIVILEGES, 2, $SE_PRIVILEGE_ENABLED, (3 * $nTokenIndex)) Else DllStructSetData($TOKEN_PRIVILEGES, 2, 0, (3 * $nTokenIndex)) EndIf DllStructSetData($TOKEN_PRIVILEGES, 2, DllStructGetData($LUID, 1), (3 * ($nTokenIndex - 1)) + 1) DllStructSetData($TOKEN_PRIVILEGES, 2, DllStructGetData($LUID, 2), (3 * ($nTokenIndex - 1)) + 2) DllStructSetData($LUID, 1, 0) DllStructSetData($LUID, 2, 0) EndIf $nTokenIndex += 1 WEnd $ret = DllCall("advapi32.dll", "int", "AdjustTokenPrivileges", "hwnd", $hToken, "int", 0, _ "ptr", DllStructGetPtr($TOKEN_PRIVILEGES), "int", DllStructGetSize($NEWTOKEN_PRIVILEGES), _ "ptr", DllStructGetPtr($NEWTOKEN_PRIVILEGES), "int*", 0) $f = DllCall("kernel32.dll", "int", "GetLastError") EndIf $NEWTOKEN_PRIVILEGES = 0 $TOKEN_PRIVILEGES = 0 $LUID = 0 If $SP_auxret[0] = 0 Then Return 0 $SP_auxret = DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hToken) If Not $ret[0] And Not $SP_auxret[0] Then Return 0 Return $ret[0] EndFunc ;==>SetPrivilege ; === SetPrivilege ===
  4. Personally, the function I posted is all I have needed beyond the many already included with your UDF. But what you suggested might be useful to others. Unfortunately, the only Active Directory installation I have access to at the moment is my employer's production system, which I cannot use for testing. I first started down the path of enumerating every child object and deleting it, then deleting the parent, but found that some objects are more difficult to enumerate and reference, and I probably just didn't know enough about what I was doing. I couldn't get the DeleteObject method working at first, but it got a lot easier once I figured out how to bind directly to the object I wanted to delete using the right credentials. Thank you for continuing to maintain this UDF. It has really helped us out!
  5. There does not seem to be a function in the UDF to delete objects that have children (leaf nodes). We have a security product in our organization that inserts child objects into computer containers, which makes it impossible to delete the computers from Active Directory using the _AD_DeleteObject function in this UDF, which calls the "Delete" method. To make this work, you have to call the "DeleteObject" method, which seems to use different semantics. I implemented it here: ; #FUNCTION# ==================================================================================================================== ; Name...........: _AD_DeleteObjectWithChildren ; Description ...: Deletes the specified object. Works on objects with children (leaf nodes) and without children. ; Syntax.........: _AD_DeleteObject($sObject) ; Parameters ....: $sObject - Object (user, group, computer etc.) to delete (FQDN or sAMAccountName) ; Return values .: Success - 1 ; Failure - 0, sets @error to: ; |1 - $sObject does not exist ; |x - Error returned by Delete function (Missing permission etc.) ; Author ........: toasterking (partially based on _AD_DeleteObject() by Jonathan Clelland; modified by water) ; Modified.......: ; Remarks .......: ; Related .......: _AD_DeleteObject, _AD_RenameObject, _AD_MoveObject ; Link ..........: https://msdn.microsoft.com/en-us/library/aa705994(v=vs.85).aspx ; Example .......: No ; =============================================================================================================================== Func _AD_DeleteObjectWithChildren($sObject) If Not _AD_ObjectExists($sObject) Then Return SetError(1, 0, 0) If StringMid($sObject, 3, 1) <> "=" Then $sObject = _AD_SamAccountNameToFQDN($sObject) ; sAMAccountName provided Local $oAdBind = $__oAD_OpenDS.OpenDSObject("LDAP://" & $sObject, $sADAdminUser, $sADAdminPassword, $__bAD_BindFlags) If @error Or Not IsObj($__oAD_Bind) Then ; login error occurred - get extended information Local $iError = @error Local $sHive = "HKLM" If @OSArch = "IA64" Or @OSArch = "X64" Then $sHive = "HKLM64" Local $sOSVersion = RegRead($sHive & "\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion") $sOSVersion = StringSplit($sOSVersion, ".") If Int($sOSVersion[1]) >= 6 Then ; Delivers detailed error information for Windows Vista and later if debugging is activated Local $aErrors = _AD_GetLastADSIError() If $aErrors[4] <> 0 Then If $__iAD_Debug = 1 Then ConsoleWrite("_AD_Open: " & _ArrayToString($aErrors, @CRLF, 1) & @CRLF) If $__iAD_Debug = 2 Then MsgBox(64, "Active Directory Functions - Debug Info - _AD_Open", _ArrayToString($aErrors, @CRLF, 1)) If $__iAD_Debug = 3 Then FileWrite($__sAD_DebugFile, @YEAR & "." & @MON & "." & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC & " " & @CRLF & _ "-------------------" & @CRLF & "_AD_Open: " & _ArrayToString($aErrors, @CRLF, 1) & @CRLF & _ "========================================================" & @CRLF) Return SetError(Dec($aErrors[4]), 0, 0) EndIf Return SetError(8, $iError, 0) Else Return SetError(8, $iError, 0) EndIf EndIf Local $vResult = $oAdBind.DeleteObject(0) ;This actually does the magic of deleting an object that has children. Method takes a single parameter and only 0 is valid. If @error Then Return SetError(@error,666,0) Return 1 EndFunc Edit: And by "implemented", I mean I found code that Jonathan Clelland and water wrote and monkeyed it until it worked for me, as I'm standing on the shoulders of giants here.
  6. I was just working on a project that involved decoding a stream of binary data from a serial port in AutoIt. It took me a few hours to figure out how to process the data efficiently in AutoIt and I did not find any helpful examples on how to do so, so I thought I would share my core example and maybe save someone else some time. There may be a more efficient way to do this, but this works well for me. #cs Author: ToasterKing This is an example of a way to parse streaming binary data that follows a strict format with a header and footer. In this example, each frame is 5 bytes with a 2-byte header of 0xD5AA and a 1-byte footer of 0xAD. The _BinaryParse() function accumulates incoming data in a buffer. Once a footer is found, it searches backward for the header, and if it is in the right position, it extracts the remaining 2 bytes in the middle, then moves on to looking for the next frame. #ce ; The data source might be something asynchronous like serial or TCP, but since this is just an example, I'm just putting the data in a variable. Local $fSomeData $fSomeData = Binary("0xD5AA24B1") ; Binary data constituting almost a complete frame. _BinaryParse($fSomeData) ; Call the function with the received data. It isn't a complete frame, so it is just stored in the buffer until more data is received. $fSomeData = Binary("0xAD62D5AA92E7AD") ; Remainder of the previous frame, one garbage byte (0x62) which should be skipped, and a complete additional frame. _BinaryParse($fSomeData) ; The function should be able to parse both frames now. Func _BinaryParse($fNewData) Local Static $fBinaryReceived = Binary("") ; Buffer for received data ConsoleWrite("Hey, the function is called!" & @CRLF) ; Add new data to the buffer. ; This ridiculous monstrosity is the only way I could find to append binary data to binary data in AutoIt. It must be converted to strings first. ; Both, one, or no substrings will begin with "0x" depending on whether they contained binary data. To be converted back to binary properly, only one instance ; of "0x" must exist at the beginning of the string. $fBinaryReceived = Binary("0x" & StringReplace(String($fBinaryReceived) & String($fNewData),"0x","")) ConsoleWrite("Data in the buffer: " & String($fBinaryReceived) & @CRLF) Local $iLength = BinaryLen($fBinaryReceived) ; Count the bytes in the data If $iLength > 0 Then Local $fBinaryReceivedTemp = $fBinaryReceived ; Create temporary copy to work on Local $fByte1,$fByte2 For $i = 1 To $iLength If BinaryMid($fBinaryReceivedTemp,$i,1) = 0xAD Then ; If the 1-byte footer found ConsoleWrite("Footer found at end of " & $i & " of " & $iLength & " bytes!" & @CRLF) If BinaryMid($fBinaryReceivedTemp,$i - 4,1) = 0xD5 And BinaryMid($fBinaryReceivedTemp,$i - 3,1) = 0xAA Then ; and the 2-byte header is found 4 bytes before that ConsoleWrite("Header found before the footer!" & @CRLF) $fByte1 = BinaryMid($fBinaryReceivedTemp,$i - 2,1) ; Get 1st byte in the body (between header and footer) $fByte2 = BinaryMid($fBinaryReceivedTemp,$i - 1,1) ; Get 2nd byte in the body (between header and footer) ConsoleWrite("Here is the critical data: " & String($fByte1) & " " & String($fByte2) & @CRLF) ; Just display the 2 bytes for demonstration purposes. Normally, you'd do something more useful with it here. EndIf $fBinaryReceived = BinaryMid($fBinaryReceivedTemp,$i + 1) ; Truncate the original data to remove all of the bytes just processed, then continue processing $fBinaryReceivedTemp EndIf Next EndIf EndFunc
  7. I think it is also worth mentioning that race conditions can occur even within a single thread as long as there is some scheduling mechanism for the code execution (à la coprocesses) and resources are shared. Race conditions are possible in an AutoIt script if, for example, code in the main loop and code in a function called by AdLibRegister() manipulate the same shared data. I started a thread a few years ago in which I went apeshit on that concept:
  8. I think it's a good idea but its success depends on how much data you can reasonably substitute for code. In other words, what types of problems that will need to be corrected in the future can you predict today? That and you're adding a second point of failure. If it stores a copy of the Pastebin config in a local file and just loads that when the Pastebin page is not accessible, and you distribute that file with the script so it initially comes with a copy, the "second point of failure" goes away.
  9. @JohnOne, agreed on all points, and good call about the less experienced being unlikely to post. I'm certainly not criticizing you for contributing! This. I don't need ego stroking per se, but I was glad to see @tarretarretarre excited about this and hoped others would join him. But people are downloading it and hopefully using it successfully. That or it's not working for them and they're moving on. I guess if we really wanted to know, we'd create a poll. I personally didn't care that much when I posted my example. My position was very much "take it or leave it" and that probably showed. I'm happy to see this developed into something more useful; I'm just not willing to spend any more time on it myself.
  10. Because the two actually have little to do with each other. A race condition doesn't occur when the CPU does more than one thing at a time; a race condition occurs when two separate code paths (each representing many, many individual CPU instructions) have each been partially executed and the next one to have a turn is not aware of what the other one has been working on and makes an assumption. Imagine you're a customer (line of code) in a store (execution environment). There are two lines (threads) of customers all waiting to check out, but only a single cashier (CPU) who services each line of customers arbitrarily (preemptive multitasking). The cashier (CPU) is processing all the transactions (instructions) that keep the store (OS) running, but you don't necessarily care how the cashier does their job because you're just a shopper (a programmer of code in a high-level language) and that's not your job. You're waiting to buy a box of allergy medication (obtain a handle to a resource) which is stocked behind the counter. When you get in line, you count the number of people in front of you and calculate that there are enough boxes of the medication on the shelf for you to get one even if every person in front of you does. Just before you get to the register, someone buys the last box. What happened? Oh sh*t, you weren't paying attention to the other line. The cashier is oblivious to your massive fail and continues processing transactions like normal. You exit the store anyway (you did no error checking) and are stungbitten by a vampire bee. Without your medication (resource) you have an allergic reaction and die. You've crashed due to a race condition! Okay, so my analogy could probably use a little work, but hopefully you get the idea. When I was learning this stuff, a video of a talk that Allen Downey gave on his book The Little Book of Semaphores and the demonstrations he gave made a lot of sense to me. Unfortunately, it appears that the video has been removed from YouTube. But look, I can still prove that it once existed! http://web.archive.org/web/20150511150444/https://www.youtube.com/watch?v=RaEUw107dpg
  11. Amazing stuff, @tarretarretarre! This is a very ambitious project. Like @JohnOne, I never fully committed to making this happen myself. The code generator I posted did enough of what I wanted it to do and I moved on. It was actually selfishly inspired by my own laziness and apathy for the process. I didn't want to have to deal with the tedium of shoehorning DLLs into AutoIt scripts again and realized that I duplicated a lot of code every time I did it, so the code generator helped me to be lazier, and I haven't looked back. But your project is bringing me a lot closer to this utopian dream of mine than I ever was before. I'm glad my humble little project inspired something bigger. I had never planned to continue it but this is what I was hoping for! I have to say, though, that I'm a little disappointed that this has been here almost a week and the only discussion I'm seeing so far is bug reports.
  12. Honestly, I probably don't know any more than you. I stopped when I reached the limit of what this code generator can do because that was all I've needed so far. If the code generator can't solve it and it's not covered on pages 1 to 8 of the linked PDF, I probably can't do it either. Good luck, though!
  13. Thanks! Mostly for speed. It's habit; I make optimizations when I see them. Try this example code. The same lookup operation takes 3 times as long with an array as with a Switch statement. My times:Lookup1 time: 5993.06858483286 msLookup2 time: 15289.7226984924 ms Global $aLookup[15][2] = [[1,"one"], _ [2,"two"], _ [3,"three"], _ [4,"four"], _ [5,"five"], _ [6,"six"], _ [7,"seven"], _ [8,"eight"], _ [9,"nine"], _ [10,"ten"], _ [11,"eleven"], _ [12,"twelve"], _ [13,"thirteen"], _ [14,"fourteen"], _ [15,"fifteen"]] Local $tTest = TimerInit() For $i = 1 To 1000000 _Lookup1("fifteen") Next ConsoleWrite("Lookup1 time: " & TimerDiff($tTest) & " ms" & @CRLF) $tTest = TimerInit() For $i = 1 To 1000000 _Lookup2("fifteen") Next ConsoleWrite("Lookup2 time: " & TimerDiff($tTest) & " ms" & @CRLF) Func _Lookup1($sName) Switch $sName Case "one" Return 1 Case "two" Return 2 Case "three" Return 3 Case "four" Return 4 Case "five" Return 5 Case "six" Return 6 Case "seven" Return 7 Case "eight" Return 8 Case "nine" Return 9 Case "ten" Return 10 Case "eleven" Return 11 Case "twelve" Return 12 Case "thirteen" Return 13 Case "fourteen" Return 14 Case "fifteen" Return 15 Case Else Return 0 EndSwitch EndFunc Func _Lookup2($sName) For $i = 1 To UBound($aLookup) - 1 If $sName = $aLookup[$i][1] Then Return $aLookup[$i][0] Next Return 0 EndFunc If you prefer arrays for readability, you're welcome to rewrite it.
  14. Thanks. I updated the link in the original post with the one Reb provided.
  15. That's not the sort of use I intended when I wrote the function, but this is AutoIt. Of course there is a way.â„¢ Try my scribblings below. If you want something wrapped up in a nice, tidy function, that's an exercise for the reader. #include <Constants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <GuiEdit.au3> $FormMain = GUICreate("Crappy Demo", 602, 297) $EditStdOut = GUICtrlCreateEdit("", 16, 16, 569, 225, BitOR($ES_AUTOVSCROLL,$ES_WANTRETURN,$WS_VSCROLL)) $ButtonTraceRoute = GUICtrlCreateButton("Trace Route!", 240, 256, 115, 25) GUISetState(@SW_SHOW) While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $ButtonTraceRoute _TraceRoute() EndSwitch WEnd Func _TraceRoute() GUICtrlSetState($ButtonTraceRoute,$GUI_DISABLE) $hRunStream = Run(@SystemDir & "\tracert.exe www.autoitscript.com",@SystemDir,@SW_HIDE,$STDOUT_CHILD) While 1 $sStreamOut = StdoutRead($hRunStream) If @error Then ExitLoop Else _GUICtrlEdit_AppendText($EditStdOut,$sStreamOut) EndIf Sleep(100) WEnd GUICtrlSetState($ButtonTraceRoute,$GUI_ENABLE) EndFunc
×
×
  • Create New...