Skip to content

Instantly share code, notes, and snippets.

@llatzhar
Created September 16, 2008 07:59
Show Gist options
  • Save llatzhar/11006 to your computer and use it in GitHub Desktop.
Save llatzhar/11006 to your computer and use it in GitHub Desktop.
record active process
require 'Win32API'
require 'kconv'
$KCODE = 's'
# user32.dll
$GetForegroundWindow = Win32API.new("user32", "GetForegroundWindow", '', 'L')
$GetWindowText = Win32API.new("user32", "GetWindowText", 'LPI', 'I')
$GetWindowThreadProcessId = Win32API.new("user32", "GetWindowThreadProcessId", 'LP', 'L')
# psapi.dll
$EnumProcessModules = Win32API.new("psapi", "EnumProcessModules", 'LPLP', 'I')
$GetModuleBaseName = Win32API.new("psapi", "GetModuleBaseName", 'LLPL', '')
$GetModuleFileNameEx = Win32API.new("psapi", "GetModuleFileNameEx", 'LLPI', 'L')
# kernel32.dll
$OpenProcess = Win32API.new("kernel32", "OpenProcess", 'LIL', 'L')
$CloseHandle = Win32API.new("kernel32", "CloseHandle", 'L', '')
class ActiveProcess
attr_accessor :start, :caption, :modules, :pid, :time
def initialize
@start = Time.now
@time = 0
hwnd = $GetForegroundWindow.call()
if hwnd == 0
@caption = "locking."
@module_size = 0
@modules = ["unknown"]
@pid = 0
return self
end
buf = "\0" * 512
$GetWindowText.call(hwnd, buf, buf.size)
@caption = buf.unpack('A*').first
buf2 = "\0" * 4
$GetWindowThreadProcessId.call(hwnd, buf2)
@pid = buf2.unpack('L').first
# PROCESS_QUERY_INFORMATION (0x0400) + PROCESS_VM_READ (0x0010)
hp = $OpenProcess.call(0x410, 0, @pid)
#puts "ProcessHandle = #{hp}"
buf3 = "\0" * 256 * 4
return_size = "\0" * 4
r = $EnumProcessModules.call(hp, buf3, buf3.size, return_size)
#p r
@module_size = return_size.unpack('L').first
@modules = buf3.unpack('L*')
if @module_size < 1
@modules = ["unknown"]
else
ma = []
@modules.each do |m|
buf4 = "\0" * 1024
$GetModuleBaseName.call(hp, m, buf4, buf4.size)
ma << buf4.unpack('A*').first
end
@modules = ma
end
$CloseHandle.call(hp)
end
end
if __FILE__ == $0
puts ActiveProcess.new.inspect
end
require 'active_process'
require 'sqlite3'
CLEAR_DB = false
class Processline
def initialize(db)
init_db(db)
end
def init_db(db)
@db = db
begin
@db.execute('drop table timeline') if CLEAR_DB
rescue SQLite3::SQLException => e
p e
end
begin
@db.execute <<END
create table timeline (
id INTEGER PRIMARY KEY,
start INTEGER,
time INTEGER,
process TEXT,
caption TEXT
);
END
puts "new table 'timeline' has been created"
rescue SQLite3::SQLException => e
# table already existed
p e
end
end
def add(process)
@db.execute('insert into timeline (start, time, process, caption) values(?, ?, ?, ?);',
process.start.to_i,
process.time,
process.modules.first,
process.caption
);
end
def show()
puts "--" * 20
today = Time.now
b = Time.local(today.year, today.month, today.day, 0, 0, 0, 0)
e = b + (24 * 60 * 60)
actions = []
@db.execute('select id, start, sum(time) as time, process, caption from (select * from timeline where ? <= start and start < ?) group by process, caption order by time;', b.to_i, e.to_i).each do |row|
actions << {
:id => row[0].to_i,
:start => Time.at(row[1].to_i),
:time => row[2].to_i,
:process => row[3],
:caption => row[4]
}
end
actions.each do |a|
h = a[:time] / 3600
m = a[:time] % 3600 / 60
s = a[:time] % 60
puts "#{sprintf("%02d:%02d:%02d", h.to_i, m.to_i, s.to_i)} #{a[:process]} #{a[:caption]}"
end
end
end
# open sqlite db
db = SQLite3::Database.new('nekotuki.db')
timeline = Processline.new(db)
# main
begin
start = Time.now
arrive = ActiveProcess.new
arrive.start = Time.now
head = arrive
loop do
if (head.pid != arrive.pid) || (head.caption != arrive.caption)
head.time = arrive.start - head.start
timeline.add(head)
timeline.show
head = arrive
end
sleep 1
arrive = ActiveProcess.new
end
ensure
#
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment