AutoHotkey Community

It is currently May 27th, 2012, 1:54 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: January 20th, 2010, 8:12 am 
Offline

Joined: January 21st, 2009, 1:06 pm
Posts: 63
Image

Description
    Submits either all processes minus exclusions or specific processes to the EmptyWorkingSet API. This API tells Windows to purge the unused memory from an application.
Features
    - On-screen log that includes the date and time as well as the process names that were submitted to EmptyWorkingSet
    - All settings saved to ini file in the scripts directory
    - User definable interval for automating process cleanup
    - All processes with exclusions can be cleaned or just specific processes
    - Able to be hidden to the system tray
    - Can be set to automatically start cleanup when launched and to start hidden in the system tray
    - Double-click on tray icon to restore from the tray
Instructions
    1 - Push "Start"
    2 - ???
    3 - Enjoy? ...
Notes
    - The inspiration for this script came from a tool I found called CleanMem. I hated relying on the scheduler service to run the tool so I made my own.
    - The only thing I would like to do further with this script is get it to clear the system cache in a similar manner to how the sysinternals CacheSet tool and CleanMem do. Any help doing this would be GREATLY appreciated.
    - Im currently running this tool on a couple SQL machines at work that were strapped for memory (98% of 4GB) because of poor code. They are all running on a 1 hour interval for cleanup and use less than 50% of that same 4GB at any time.
    - Any time the settings are changed you need to press "Start" again to apply the new settings.
Download links

As always, any tips, suggestions, or constructive criticism is not only welcomed, but encouraged!

Code:
; =============== Auto-execute ===============
#NoEnv
SendMode, Input
SetWorkingDir, %A_ScriptDir%
SetTitleMatchMode, 3
DetectHiddenWindows, On

IfExist, ram.ico
   Menu, Tray, Icon, ram.ico
Menu, Tray, NoStandard
Menu, Tray, Add, Show Window, ShowWindow
Menu, Tray, Add, Exit, GuiClose
Menu, Tray, Default, Show Window

; =============== Variables ===============
Version = 1.1.0

; =============== GUI ===============
GoSub, ReadINI

Gui, Add, Button, x15 y395 w80 h30, Start
Gui, Add, Button, x175 y395 w70 h30, Hide
Gui, Add, Button, x255 y395 w70 h30, Exit
Gui, Add, Tab, x0 y5 w340 h385, Status|Settings|About
Gui, Tab, Status
   Gui, Add, Edit, x20 y60 w300 h300 +ReadOnly -Wrap
Gui, Tab, Settings
   Gui, Font, S12 Bold,
   Gui, Add, Text, x130 y30, Interval
   Gui, Add, Text, x135 y90, Type
   Gui, Add, Text, x130 y280, Startup
   Gui, Font,,
   Gui, Add, Edit, x110 y60 w100 h20 vRunInterval, %RunInterval%
   Gui, Add, Text, x+10 y60 w100 h30, min
   Gui, Add, Radio, vRunType x10 y120, All processes (Exclusions)
   Gui, Add, Radio, x170 y120, Specific process (Inclusions)
   Gui, Add, Edit, vExclusions x15 y150 w150 h100 -Wrap, %Exclusions%
   Gui, Add, Edit, vInclusions x175 y150 w150 h100 -Wrap, %Inclusions%
   Gui, Add, Checkbox, vAutorun Checked%Autorun% x90 y310, Auto-run
   Gui, Add, Checkbox, vHide Checked%Hide% x180 y310, Start hidden
   Gui, Add, Button, x120 y355, Save Settings
Gui, Tab, About
   Gui, Font, S14
   Gui, Add, Text, x36 y100 w250 h150 , Written by:`n`nMatthew Giffin`nstrictlyfocused02@gmail.com
   Gui, Font,,
Gui, Show, h430 w340, Memory Cleanup v%Version%

If RunType = 1
   Control, Check,, Button4, Memory Cleanup v%Version%
If RunType = 2
   Control, Check,, Button5, Memory Cleanup v%Version%   
If Hide = 1
   GoSub, ButtonHide
If Autorun = 1
   GoSub, ButtonStart

Return

; =============== GUI Sub-routines ===============
ButtonExit:
GuiClose:
   ExitApp

GuiSize:
   If A_EventInfo = 1
      WinHide, Memory Cleanup v%Version%
   Return

ButtonHide:
   WinHide, Memory Cleanup v%Version%
   Return

ShowWindow:
   WinShow, Memory Cleanup v%Version%
   WinWait, Memory Cleanup v%Version%
   WinActivate, Memory Cleanup v%Version%
   Return

ButtonStart:
   Gui, Submit, NoHide
   GoSub, MemoryCleanup
   GoSub, SetInterval
   Return
 
SetInterval:
   AHKRunInterval := RunInterval * 60000
   SetTimer, MemoryCleanup, %AHKRunInterval%
   Return

ReadINI:
   IfExist, settings.ini
   {
      IniRead, RunInterval, settings.ini, Interval, Interval
      IniRead, RunType, settings.ini, Type, RunType
      IniRead, Exclusions, settings.ini, Type, Exclusions
      IniRead, Inclusions, settings.ini, Type, Inclusions
      IniRead, Autorun, settings.ini, Launch, Autorun
      IniRead, Hide, settings.ini, Launch, Hide
      If not Exclusions
         Exclusions = One process name per line
      If Exclusions
         StringReplace, Exclusions, Exclusions, `,, `n, All
      If not Inclusions
         Inclusions = One process name per line
      If Inclusions
         StringReplace, Inclusions, Inclusions, `,, `n, All
      Return
   }
   IfNotExist, settings.ini
   {
      RunInterval = 30
      RunType = 1
      Exclusions = One process name per line
      Inclusions = One process name per line
      Autorun = 0
      Hide = 0
      Return
   }

ButtonSaveSettings:
   Gui, Submit, NoHide
   If Exclusions = One process name per line
      Exclusions =
   If Inclusions = One process name per line
      Inclusions =
   StringReplace, Exclusions, Exclusions, `n, `,, All
   StringReplace, Inclusions, Inclusions, `n, `,, All
   IniWrite, %RunInterval%, settings.ini, Interval, Interval
   IniWrite, %RunType%, settings.ini, Type, RunType
   IniWrite, %Exclusions%, settings.ini, Type, Exclusions
   IniWrite, %Inclusions%, settings.ini, Type, Inclusions
   IniWrite, %Autorun%, settings.ini, Launch, Autorun
   IniWrite, %Hide%, settings.ini, Launch, Hide
   MsgBox, Settings saved!`n`nTip: Press "Start" now to apply these settings without having to restart the application.
   Return

; =============== Bread and Butter ===============
MemoryCleanup:
   ProcList := CMDret("tasklist /fo CSV")  ;Send "tasklist" to cmdret
   Loop, Parse, ProcList, `n
   {
      If A_Index < 4  ;The first 4 lines are always junk\column|row seperators\blank
         Continue
      StringSplit, ProcArray, A_LoopField, `,  ;Split apart using a comma delimeter
      StringReplace, ProcArray1, ProcArray1, `",, 1  ;Process Name
      StringReplace, ProcArray2, ProcArray2, `",, 1  ;PID
      If RunType = 1
      {
         StringReplace, Exclusions, Exclusions, `n, `,, All
         If ProcArray1 in %Exclusions%
            Continue
         Else
         {
            GO := CleanMemory(ProcArray2)
            If GO = 1  ;Function returned 1 (i.e. success)
            {
               ControlGetText, OnScrLog, Edit1, Memory Cleanup v%Version%
               ControlSetText, Edit1, %OnScrLog%`r`n`r`n%A_MMM%-%A_DD%-%A_YYYY% %A_Hour%:%A_Min%:%A_Sec%:%A_MSec% - Cleaned "%ProcArray1%", Memory Cleanup v%Version%
               SendMessage, 0x115, 7, 0, Edit1, Memory Cleanup v%Version%
            }
         }
      }
      If RunType = 2
      {
         StringReplace, Inclusions, Inclusions, `n, `,, All
         If ProcArray1 in %Inclusions%
         {
            GO := CleanMemory(ProcArray2)
            If GO = 1  ;Function returned 1 (i.e. success)
            {
               ControlGetText, OnScrLog, Edit1, Memory Cleanup v%Version%
               ControlSetText, Edit1, %OnScrLog%`r`n`r`n%A_MMM%-%A_DD%-%A_YYYY% %A_Hour%:%A_Min%:%A_Sec%:%A_MSec% - Cleaned "%ProcArray1%", Memory Cleanup v%Version%
               SendMessage, 0x115, 7, 0, Edit1, Memory Cleanup v%Version%
            }
         }
      }
   }
   Return
   
; =============== Functions ===============

;A function that retreives the process handle from a PID and sends it to the EmptyWorkingSet API.  Returns 1 for success, NULL (blank) on failure
CleanMemory(PID)  ;Written with help from "Temp01" on the AHK IRC chat (thank you again, temp01!!!)
{
   Process, Exist  ;Sets ErrorLevel to the PID of this running script
   h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ErrorLevel)  ;Get the handle of this script with PROCESS_QUERY_INFORMATION (0x0400)
   DllCall("Advapi32.dll\OpenProcessToken", "UInt", h, "UInt", 32, "UIntP", t)  ;Open an adjustable access token with this process (TOKEN_ADJUST_PRIVILEGES = 32)
   VarSetCapacity(ti, 16, 0)  ;Structure of privileges
   NumPut(1, ti, 0)  ;One entry in the privileges array...
   DllCall("Advapi32.dll\LookupPrivilegeValueA", "UInt", 0, "Str", "SeDebugPrivilege", "Int64P", luid)  ;Retrieves the locally unique identifier of the debug privilege:
   NumPut(luid, ti, 4, "int64")
   NumPut(2, ti, 12)  ;Enable this privilege: SE_PRIVILEGE_ENABLED = 2
   DllCall("Advapi32.dll\AdjustTokenPrivileges", "UInt", t, "Int", false, "UInt", &ti, "UInt", 0, "UInt", 0, "UInt", 0)  ;Update the privileges of this process with the new access token:
   DllCall("CloseHandle", "UInt", h)  ;Close this process handle to save memory

   hModule := DllCall("LoadLibrary", "Str", "Psapi.dll")  ;Increase performance by preloading the libaray
   h := DllCall("OpenProcess", "UInt", 0x400|0x100, "Int", false, "UInt", pid)  ;Open process with: PROCESS_QUERY_INFORMATION (0x0400) | PROCESS_SET_QUOTA (0x100)
   e := DllCall("psapi.dll\EmptyWorkingSet", "UInt", h)
   DllCall("CloseHandle", "UInt", h)  ;Close process handle to save memory
   DllCall("FreeLibrary", "UInt", hModule)  ;Unload the library to free memory
   Return e
}

;CMDret can be used to retrieve and store output from console programs in a variable without displaying the console window
CMDret(CMDin, WorkingDir=0)  ;by corrupt (http://www.autohotkey.com/forum/topic8606.html)
{
  Global cmdretPID
  tcWrk := WorkingDir=0 ? "Int" : "Str"
  idltm := A_TickCount + 20
  CMsize = 1
  VarSetCapacity(CMDout, 1, 32)
  VarSetCapacity(sui,68, 0)
  VarSetCapacity(pi, 16, 0)
  VarSetCapacity(pa, 12, 0)
  Loop, 4 {
    DllCall("RtlFillMemory", UInt,&pa+A_Index-1, UInt,1, UChar,12 >> 8*A_Index-8)
    DllCall("RtlFillMemory", UInt,&pa+8+A_Index-1, UInt,1, UChar,1 >> 8*A_Index-8)
  }
  IF (DllCall("CreatePipe", "UInt*",hRead, "UInt*",hWrite, "UInt",&pa, "Int",0) <> 0) {
    Loop, 4
      DllCall("RtlFillMemory", UInt,&sui+A_Index-1, UInt,1, UChar,68 >> 8*A_Index-8)
    DllCall("GetStartupInfo", "UInt", &sui)
    Loop, 4 {
      DllCall("RtlFillMemory", UInt,&sui+44+A_Index-1, UInt,1, UChar,257 >> 8*A_Index-8)
      DllCall("RtlFillMemory", UInt,&sui+60+A_Index-1, UInt,1, UChar,hWrite >> 8*A_Index-8)
      DllCall("RtlFillMemory", UInt,&sui+64+A_Index-1, UInt,1, UChar,hWrite >> 8*A_Index-8)
      DllCall("RtlFillMemory", UInt,&sui+48+A_Index-1, UInt,1, UChar,0 >> 8*A_Index-8)
    }
    IF (DllCall("CreateProcess", Int,0, Str,CMDin, Int,0, Int,0, Int,1, "UInt",0, Int,0, tcWrk, WorkingDir, UInt,&sui, UInt,&pi) <> 0) {
      Loop, 4
        cmdretPID += *(&pi+8+A_Index-1) << 8*A_Index-8
      Loop {
        idltm2 := A_TickCount - idltm
        If (idltm2 < 10) {
          DllCall("Sleep", Int, 10)
          Continue
        }
        IF (DllCall("PeekNamedPipe", "uint", hRead, "uint", 0, "uint", 0, "uint", 0, "uint*", bSize, "uint", 0 ) <> 0 ) {
          Process, Exist, %cmdretPID%
          IF (ErrorLevel OR bSize > 0) {
            IF (bSize > 0) {
              VarSetCapacity(lpBuffer, bSize+1)
              IF (DllCall("ReadFile", "UInt",hRead, "Str", lpBuffer, "Int",bSize, "UInt*",bRead, "Int",0) > 0) {
                IF (bRead > 0) {
                  TRead += bRead
                  VarSetCapacity(CMcpy, (bRead+CMsize+1), 0)
                  CMcpy = a
                  DllCall("RtlMoveMemory", "UInt", &CMcpy, "UInt", &CMDout, "Int", CMsize)
                  DllCall("RtlMoveMemory", "UInt", &CMcpy+CMsize, "UInt", &lpBuffer, "Int", bRead)
                  CMsize += bRead
                  VarSetCapacity(CMDout, (CMsize + 1), 0)
                  CMDout=a   
                  DllCall("RtlMoveMemory", "UInt", &CMDout, "UInt", &CMcpy, "Int", CMsize)
                  VarSetCapacity(CMDout, -1)   ; fix required by change in autohotkey v1.0.44.14
                }
              }
            }
          }
          ELSE
            break
        }
        ELSE
          break
        idltm := A_TickCount
      }
      cmdretPID=
      DllCall("CloseHandle", UInt, hWrite)
      DllCall("CloseHandle", UInt, hRead)
    }
  }
  IF (StrLen(CMDout) < TRead) {
    VarSetCapacity(CMcpy, TRead, 32)
    TRead2 = %TRead%
    Loop {
      DllCall("RtlZeroMemory", "UInt", &CMcpy, Int, TRead)
      NULLptr := StrLen(CMDout)
      cpsize := Tread - NULLptr
      DllCall("RtlMoveMemory", "UInt", &CMcpy, "UInt", (&CMDout + NULLptr + 2), "Int", (cpsize - 1))
      DllCall("RtlZeroMemory", "UInt", (&CMDout + NULLptr), Int, cpsize)
      DllCall("RtlMoveMemory", "UInt", (&CMDout + NULLptr), "UInt", &CMcpy, "Int", cpsize)
      TRead2 --
      IF (StrLen(CMDout) > TRead2)
        break
    }
  }
  StringTrimLeft, CMDout, CMDout, 1
  Return, CMDout
}


/*
>>>>CHANGELOG<<<<

1.0 (12-23-2009)
   - Original script
1.1 (10-24-2009)
   - Removed need for empty.exe
   -- Added CleanMemory function which uses the same API (EmptyWorkingSet) found in empty.exe


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 23rd, 2010, 11:40 am 
Offline

Joined: January 21st, 2009, 1:06 pm
Posts: 63
Anyone tried it? Comments?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 26th, 2010, 9:32 am 
strictlyfocused02 wrote:
Anyone tried it? Comments?
Do you have another version without tasklist /F CSV ?


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: January 28th, 2010, 9:39 am 
Offline

Joined: January 21st, 2009, 1:06 pm
Posts: 63
rooolle wrote:
strictlyfocused02 wrote:
Anyone tried it? Comments?
Do you have another version without tasklist /F CSV ?


Can I ask why? Based on your request Ive got a few different ideas on how to return a list of running processes with their PID. Im assuming an older copy of windows that doesnt support that command?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 28th, 2010, 11:26 am 
strictlyfocused02 wrote:
rooolle wrote:
strictlyfocused02 wrote:
Anyone tried it? Comments?
Do you have another version without tasklist /F CSV ?


Can I ask why? Based on your request Ive got a few different ideas on how to return a list of running processes with their PID. Im assuming an older copy of windows that doesnt support that command?
Some services missing and i dont want to start them.


Code:
C:\Documents and Settings\xx> TASKLIST /S system /FO LIST
ERROR: The RPC server is unavailable.

C:\Documents and Settings\xx>tasklist
ERROR: Invalid namespace.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: February 28th, 2010, 2:31 pm 
Offline

Joined: February 16th, 2010, 4:01 am
Posts: 60
Did you also look at this thread?
http://www.autohotkey.com/forum/topic32876.html


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 3rd, 2010, 6:23 pm 
Offline

Joined: January 21st, 2009, 1:06 pm
Posts: 63
strictlyfocused02 wrote:
- The only thing I would like to do further with this script is get it to clear the system cache in a similar manner to how the sysinternals CacheSet tool and CleanMem do. Any help doing this would be GREATLY appreciated.


Bump in hopes that someone can help me with this. Ive played around with it for a few days and am striking out. Any ideas?

Edit - Heres a related thread I made a while back:
http://www.autohotkey.com/forum/viewtopic.php?t=53214


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: June 3rd, 2010, 7:07 pm 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
strictlyfocused02 wrote:
strictlyfocused02 wrote:
- The only thing I would like to do further with this script is get it to clear the system cache in a similar manner to how the sysinternals CacheSet tool and CleanMem do. Any help doing this would be GREATLY appreciated.


Bump in hopes that someone can help me with this. Ive played around with it for a few days and am striking out. Any ideas?

Edit - Heres a related thread I made a while back:
http://www.autohotkey.com/forum/viewtopic.php?t=53214



Idea: ask for help in help forum...

and/or read the doc for cache set tool for how to...

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: Relayer and 16 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group