タグ:AutoHotKey ( 76 ) タグの人気記事

AutoHotKey_Lで、プロセス間通信経由して一般権限でRunしてみた。ver.1.2

 UIPIの制限を回避するため、常駐AHKは管理者権限で実行しているのだが、それゆえにRunした時に不要な特権が付与されてしまう。それを回避する手段はいくつかあるものの、どれも一長一短で、最終的に「一般権限の常駐AHKにプロセス間通信でパスを送ってRun」に行きついた。最初からそうしとけって話だが、旧人類なので常駐増やしたくないのだ!

 Receive2Run.ahkを一般権限で常駐させて、管理者権限AHKからRunNEXすれば、R2Rが代わりにRunしてくれる。

 "|"はEverythingにクエリ送るとき使ってたので、区切り文字はAHKらしく"`n"にした。

; 管理者権限のAHKに書くやつ

RunNEX(Cmdline, WorkDir = "", Opt = "", ByRef Pid = "") {
  SetTitleMatchMode 2
  DetectHiddenWindows On
  
  sig := "RunNEX:"
  
  SendHwnd := WinExist("Receive2Run. ahk_class AutoHotkey")
  if (0 == SendHwnd) {
    MsgBox, 262160, , Receive2Runが見つかりません。
    return
  }
  
  if !WorkDir {
    WorkDir := A_WorkingDir
  }
  
  StringToSend := sig Cmdline "`n" WorkDir "`n" Opt
  
  Result := Send_WM_COPYDATA(StringToSend, "ahk_id " SendHwnd)
  if (0 < Result) {
    Pid := Result
  } else {
    MsgBox,Err!`n%Result%

  }
}

;http://www.autohotkey.com/community/viewtopic.php?t=76704
Send_WM_COPYDATA(ByRef StringToSend, ByRef TargetScriptTitle) {
  PtrSize := A_PtrSize ? A_PtrSize : 4
  VarSetCapacity(CopyDataStruct, 3*PtrSize, 0)
  SizeInBytes := (StrLen(StringToSend) + 1) * (A_IsUnicode ? 2 : 1)
  NumPut(SizeInBytes, CopyDataStruct, PtrSize)
  NumPut(&StringToSend, CopyDataStruct, 2*PtrSize)
  
  SendMessage, 0x4a, 0, &CopyDataStruct,, %TargetScriptTitle%
  return ErrorLevel
}

;/////////////////////////////////////////////////////////////////////////////////////
;
; Receive2Run.ahk
;
;/////////////////////////////////////////////////////////////////////////////////////
  #SingleInstance, Force
  #NoEnv
  #Persistent
  SetBatchLines, -1
  Menu, Tray, Icon, SHELL32.dll, 262
  
  sig := "RunNEX:"
  
  if A_IsAdmin {
    MsgBox, 262160, , 管理者権限で起動しないでください。
    ExitApp
  }
  
  OnMessage(0x4a, "Receive_WM_COPYDATA")
return

;http://www.autohotkey.com/community/viewtopic.php?t=76704
Receive_WM_COPYDATA(wParam, lParam) {
  global sig
  PtrSize:=A_PtrSize ? A_PtrSize : 4
  StringAddress := NumGet(lParam + 2*PtrSize)
  CopyOfData := StrGet(StringAddress)
  
  if RegExMatch(CopyOfData, "^" sig "([^\n]+)(?:\n([^\n]*))?(?:\n([^\n]*))?(?:\n([^\n]*))?$", $) {
    TrgPath := $1
    WorkDir := $2
    Opt := $3
    
    TrgPid := 0
    Run, %TrgPath%, %WorkDir%, %Opt%, TrgPid
  } else {
    MsgBox, Err!`n%CopyOfData%

  }
  return TrgPid
}

 メッセージ受け取ってRunとかいかにも悪用されそうなので、とりあえず符丁つけてみた。使うときは双方のsigを適当に書き換えてね。
 送り主を確認するとか他にやるべきことがあるのでは?という気もするが、所詮「とりあえず」なんで……。

 他の手段、「一般ユーザーでRunAS」「CreateProcessWithTokenWでShellから一般権限をコピー」「Shellに引数をつけてRun」とかあるのだけど――。RunAsはパスワードを平文で記録したくないのでNG。CreateProcessWithTokenWは複雑で、フォーラムにあったのコピペで試してたけど、動作したりしなかったり。で、Shellに.lnkを実行させるハックを愛用してたのだけど、これも近頃調子悪くなってしまい、諦めて常駐増やしたっちゅー……。



オマケ
[PR]
by LordNoesis | 2018-06-15 19:08 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、OnTopReplicaを少し便利に。ver.1.0.1

 高解像度モニタやマルチモニタが便利なのは「視線移動だけで数多のウィンドウを確認できる」からだけど、文章でもない限りサムネで十分というか、むしろサムネの方が同時表示ウィンドウ数増えてよくね?と思ったので、それっぽいソフトを探したけどなかったから、既存のソフトを組み合わせてなんとかするの巻。

 というわけで、ウィンドウの縮小クローンを作成するソフト「OnTopReplica」が便利なのだけど、大抵の操作は縮小クローンより元ウィンドウでした方がよいので、OTRをクリックしたら元ウィンドウをアクティブにするAHK書いた。

;--------------------------------------------------------------------------------------
; OnTopReplica
;--------------------------------------------------------------------------------------
#IfWinActive ahk_exe OnTopReplica.exe
~LButton::return

LButton Up::
  if (400 < A_TimeSincePriorHotkey)
    return
  
  WHwnd := WinExist()
  
  BlockInput, On
  Send, {RButton}{Up}{Down 2}{Enter}
  WinWaitNotActive, ahk_id %WHwnd%, , 0.5
  WinActivate, ahk_id %WHwnd%
  BlockInput, Off
return

 メインの作業をしている裏で、入力に間のある作業(重い対話型ソフトとか、チャットやゲーム)をしている状況で、モニタの隅やセカンダリモニタあたりに縮小クローンを配置して、横目で見て変化があったらクリックするだけで操作可能になる。便利。

 なお、「元ウィンドウなどいらん、縮小ウィンドウを左クリックできれば十分!」という場合は「窓の化身」を使う。


[PR]
by LordNoesis | 2018-04-09 22:45 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、Stellarisのカーソル移動による自動スクロールを防止した。

 Stellarisやってて、ウィンドウ端にカーソル移動するとスクロールする仕様がウザったいのだが、設定でOFFにできないっぽいので、力業で封じてみた。

 まあ単に、監視して、カーソルがウィンドウ端に行ったらウィンドウ非アクティブにするだけなんで、ちょっと書き換えれば他でも使える。フルスクリーンとか知らぬ。

;------------------------------------------------------------
; Stellaris
;------------------------------------------------------------
#IfWinActive Stellaris ahk_class SDL_app ahk_exe stellaris.exe

F12::  ; マウスカーソルでスクロールしないようにする
  StlrsMargin := 2
  
  StellarisHwnd := WinExist()
  VarSetCapacity(CR, 16)
  DllCall("GetClientRect", Ptr, StellarisHwnd, Ptr, &CR)
  CW := NumGet(CR, 8, "Int")
  CH := NumGet(CR, 12, "Int")
  
  WinGetPos, , , WW, WH
  BW := (WW - CW) // 2
  
  StlrsX := BW + StlrsMargin
  StlrsY := WH - CH - BW + StlrsMargin
  StlrsX2 := BW + CW - StlrsMargin
  StlrsY2 := WH - BW - StlrsMargin
  
  SetTimer, StlrsChk, 250
return

StlrsChk:
  IfWinNotExist, ahk_id %StellarisHwnd%
  {
    SetTimer, StlrsChk, Off
    return
  }
  IfWinNotActive
    WinWaitActive
  
  MouseGetPos, MX, MY
  if (StlrsX >= MX) || (StlrsY >= MY) || (StlrsX2 < MX) || (StlrsY2 < MY)
    WinActivate, Program Manager ahk_class Progman ahk_exe explorer.exe
return

 AHKってクライアント領域の取得できないんか……。


[PR]
by LordNoesis | 2018-02-21 23:32 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、AviUtlのバッチ登録を自動化した。

 AviUtlで複数ファイルをエンコードする場合「バッチ登録」を使うのだけど、手作業で出力ファイル名入力するのが面倒すぎたので自動化した。

 変換したい動画のパスリスト(\n区切り)をクリップボードに入れて、AviUtlメインウィンドウでF12打鍵すれば登録開始。
 出力ファイルは"元ファイル名.設定した拡張子"で、重複してれば接尾辞"_[n]"で回避。
 使用前に"OutputPluginNum"と"SaveFileExt"を設定すべし。

;--------------------------------------------------------------------------------------
; AviUtl
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class AviUtl ahk_exe Aviutl.exe

F12::  ; クリップボードのパスをバッチ登録
  
  OutputPluginNum := 1  ; "プラグイン出力"で選択するプラグインの番号。1番上は1。
  SaveFileExt := "mp4"  ; 出力ファイルの拡張子。
  
  
  
  PathList := Clipboard
  
  WinGet, WHwnd, ID
  WinGet, ExePath, ProcessPath
  SplitPath, ExePath, , ExeDir
  IfExist, %ExeDir%\batch*.aup
  {
    MsgBox, 262691, , バッチ登録されたプロジェクトが存在します`n既存のプロジェクトを削除しますか?
    IfMsgBox, Cancel
      return
    IfMsgBox, Yes
      FileRecycle, %ExeDir%\batch*.aup
  }
  
  StringReplace, PathList, PathList, `n, `n, UseErrorLevel
  MaxNum := ErrorLevel
  
  Loop, Parse, PathList, `n, `"
  {
    TipView(A_Index "/" MaxNum)
    
    FilePath := A_LoopField
    IfNotExist, %FilePath%
      continue
    
    SplitPath, FilePath, , FileDir, , FileNoExt
    
    SaveFilePath := FileDir "\" FileNoExt "." SaveFileExt
    while FileExist(SaveFilePath)
      SaveFilePath := FileDir "\" FileNoExt "_[" A_Index "]." SaveFileExt
    
    WinMenuSelectItem, ahk_id %WHwnd%, , ファイル, 1&  ; "開く"
    WinWait, ファイルを開く ahk_class #32770 ahk_exe Aviutl.exe
    ControlSetText, Edit1, %FilePath%  ; "ファイル名"
    Sleep, 100
    ControlClick, Button2, , , L, 2  ; "開く"
    WinWaitClose
    
    WinMenuSelectItem, ahk_id %WHwnd%, , ファイル, プラグイン出力, %OutputPluginNum%&
    WinWait, ahk_class #32770 ahk_exe Aviutl.exe
    ControlSetText, Edit1, %SaveFilePath%  ; "ファイル名"
    Sleep, 100
    ControlClick, Button5, , , L, 2  ; "バッチ登録"
    WinWaitClose
  }
  
  TipView("FIN")
return


;--------------------------------------------------------------------------------------
; TipView.ahk
;--------------------------------------------------------------------------------------

TipView(TextBuf = "", Timer = 3000, X = "", Y = "", SW = 0) {
  if SW
    CoordMode, ToolTip

  ToolTip, %TextBuf%, X, Y
  if !Timer
    Timer := "Off"
  SetTimer, TipClose, %Timer%
}

TipClose:
  SetTimer, TipClose, Off
  ToolTip
return


[PR]
by LordNoesis | 2017-05-17 18:29 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、標準出力を得たい……。

 以前見つけた関数だと上手く動かないことがあったのでフォーラム検索したら、もっと新しいやつを見つけた。見つけたんだが、標準出力が多いと文字化けすることが発覚。ReadFileでバイト単位で取得したデータをそのままデコードしてるせいだと思うが、AHKで文字列でないデータを操作とか苦行の予感がするので、Fileオブジェクトで文字単位で取得してごまかした。
 文字化けはなくなったが、本当にこれで問題ないのかは解らん。

; https://autohotkey.com/board/topic/54559-stdin/#entry687172

  MsgBox % sOutput := StdoutToVar_CreateProcess("tasklist /s " A_ComputerName)

StdoutToVar_CreateProcess(psCmd, psInput="", psEncoding:="CP0", psDir:="", ByRef pnExitCode:=0) {
  
  DllCall("CreatePipe", PtrP, hStdInRd, PtrP, hStdInWr, Ptr, 0, UInt, 0)
  DllCall("CreatePipe", PtrP, hStdOutRd, PtrP, hStdOutWr, Ptr, 0, UInt, 0)
  DllCall("SetHandleInformation", Ptr, hStdInRd, Uint, 1, Uint, 1)
  DllCall("SetHandleInformation", Ptr, hStdOutWr, UInt, 1, UInt, 1)
  
   VarSetCapacity(pi, (A_PtrSize == 4) ? 16 : 24, 0)
  siSz := VarSetCapacity(si, (A_PtrSize == 4) ? 68 : 104, 0)
  NumPut(siSz, si, 0, "UInt")
  NumPut(0x100, si, (A_PtrSize == 4) ? 44 : 60, "UInt")
  NumPut(hStdInRd, si, (A_PtrSize == 4) ? 56 : 80, "Ptr")
  NumPut(hStdOutWr, si, (A_PtrSize == 4) ? 60 : 88, "Ptr")
  NumPut(hStdOutWr, si, (A_PtrSize == 4) ? 64 : 96, "Ptr")
  
  If (!DllCall("CreateProcess", Ptr, 0, Ptr, &psCmd, Ptr, 0, Ptr, 0, Int, True, UInt, 0x08000000
   , Ptr, 0, Ptr, psDir ? &psDir : 0, Ptr, &si, Ptr, &pi))
   return
   , DllCall("CloseHandle", Ptr, hStdOutWr)
   , DllCall("CloseHandle", Ptr, hStdOutRd)
   , DllCall("CloseHandle", Ptr, hStdInRd)
  
  DllCall("CloseHandle", Ptr, hStdOutWr ) ; The write pipe must be closed before reading the stdout.
  
  if (psInput != "")
   FileOpen(hStdInWr, "h", psEncoding).Write(psInput)
   DllCall("CloseHandle", "Ptr", hStdInWr)
  
  
; ################################################################################
  
  
  StdOutBuf := FileOpen(hStdOutRd, "h", psEncoding)
  StrBuf := 1
  while StrLen(StrBuf) {
   StrBuf := StdOutBuf.Read(2047)
   sOutPut .= StrBuf
  }
  
  
; ################################################################################
  
  
  DllCall("GetExitCodeProcess", Ptr, NumGet(pi, 0), UIntP, pnExitCode)
  DllCall("CloseHandle", Ptr, NumGet(pi, 0) )
  DllCall("CloseHandle", Ptr, NumGet(pi, A_PtrSize) )
  DllCall("CloseHandle", Ptr, hStdOutRd )
return sOutput
}


[PR]
by LordNoesis | 2016-02-09 20:00 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、Opera12の起動を便利にしてみた。 ver.2.3.1

 セッション変換に失敗することがあったので1行だけ修正。今更使う人もいないと思うが。

; --------- --------- --------- --------- ---------
; RunOpera.ahk ver.2.3.1
; --------- --------- --------- --------- ---------

#WinActivateForce

  OperaPath := "R:\Opera"  ; Opera.exeの存在するパス。末尾"\"は不可。
  
  if %0%  ; 引数があった場合、Operaのパスと見なす
    OperaPath = %1%
  
  SessionsPath := OperaPath "\profile\sessions"  ; セッションフォルダのフルパスを指定。末尾"\"は不可。
  BookmarksPath := OperaPath "\profile\bookmarks.adr"  ; bookmarks.adrのフルパスを指定。
  
  TimeLimit := 30  ; 最終セッション退避確認ダイアログを自動でスキップするまでの秒数。
  
  AutoConvSW := 1  ; 最終セッションを退避させる場合、自動でブックマークに変換する設定。 0:変換しない。 1:変換する。
  ACMoveSW := 1  ; 自動変換(↑)したセッションを隔離する設定。 0:隔離しない。 1:隔離する。
  
  StackSW := 1  ; スタックの設定。 0:無視する。 1:スタックごとにフォルダを分ける。
  
  HisReadSW := 0  ; タブ履歴(タブで表示したページの履歴)の設定。 0:最新のみ読み込む。 1:すべて読み込む。
  His0PrefixSW := 0  ; タブ履歴がなかった場合のプレフィックスの設定。 0:なし。 1:0を明示する。
  
  WriteTrgSW := 1  ; ブックマーク情報を書き込む場所の設定。 0:セッションフォルダにテキストで保存。 1:bookmarks.adrに書き込む。
  
; --------- --------- --------- --------- ---------
  
  IfNotExist, %SessionsPath%\
  {
    MsgBox, 16, , セッションフォルダが見つかりません。`n%SessionsPath%
    ExitApp
  }
  If WriteTrgSW {
    IfNotExist, %BookmarksPath%
    {
      MsgBox, 16, , bookmarks.adrが見つかりません。`n%BookmarksPath%
      ExitApp
    }
  }
  
  IfNotExist, %SessionsPath%\autosave.win
  {
    IfExist, %SessionsPath%\autosave.win.bak
      FileMove, %SessionsPath%\autosave.win.bak, %SessionsPath%\autosave.win
  }
  IfExist, %SessionsPath%\autosave.win
  {
    FileCopy, %SessionsPath%\autosave_RunOpBak.win, %SessionsPath%\autosave_RunOpBak2.win, 1  ; ↓セッション退避etc.を実行しない時も念のため2世代バックアップ。
    FileCopy, %SessionsPath%\autosave.win, %SessionsPath%\autosave_RunOpBak.win, 1
    GoSub, SessionAnalyze
  }
  
  FileCopy, %OperaPath%\ui\fastforward_backup.ini, %OperaPath%\ui\fastforward.ini, 1  ; アップデートのたびにFastForward.iniが初期化される問題の対策。
  
  Run, %OperaPath%\opera.exe, , , OpPid
  WinWait, ahk_pid %OpPid%, , 60
  if !ErrorLevel {
    ifWinExist, Opera へようこそ ahk_pid %OpPid%
    {
      WinActivate
      WinWaitClose
    }
  } else {
    return
  }
  
  WinWait, マスターパスワードを入力してください ahk_pid %OpPid%, , 5
  If ErrorLevel
    return
  WinSet, Topmost, ON
  WinActivate
  Sleep, 300
  
ExitApp

; --------- --------- --------- --------- ---------

SessionAnalyze:
  FileRead, OSession, *P65001 *t %SessionsPath%\autosave.win
  If ErrorLevel {
    MsgBox, 48, , Sessionの読み込みに失敗しました。`n%SessionsPath%\autosave.win
    return
  }
  
  Idx := 0
  WinTitles := ""
  Loop {
    Idx := RegExMatch(OSession, "\[(\d+)history url\][\s\S]+?count=(\d+)", $, Idx + 1)
    If !Idx
      Break
    WinNum := $1
    HisNum := $2 - 1
    HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
    WinTitles .= " " HisTitle "`n"
  }
  If !WinTitles
    return
    
  SetTimer, RenewCount, 1000
  MsgBox, 259, 退避確認(30秒後に通常起動), 起動時に最終セッションを退避しますか?`n`n◆最終セッションの内容◆`n%WinTitles%, %TimeLimit%
  SetTimer, RenewCount, Off
  IfMsgBox, Yes
  {
    TimeNum := A_Now
    BackupName := TimeNum ".win"
    Loop {
      FileMove, %SessionsPath%\autosave.win, %SessionsPath%\%BackupName%
      If !ErrorLevel  ; 最終セッションのリネームに成功なら
        Break
      BackupName := TimeNum "_" A_Index ".win"
    }
    FileDelete, %SessionsPath%\autosave.win.bak
    If AutoConvSW
      GoSub, SessionConvert
  }
  IfMsgBox, Cancel
    ExitApp
return

; --------- --------- --------- --------- ---------

RenewCount:
  IfWinExist, 退避確認( ahk_class #32770
  {
    TimeLimit--
    WinSetTitle, 退避確認(%TimeLimit%秒後に通常起動)
    if !TimeLimit
      SetTimer, RenewCount, Off
  }
return

; --------- --------- --------- --------- ---------

SessionConvert:
  If WriteTrgSW
    FileCopy, %BookmarksPath%, %BookmarksPath%_%A_Now%  ; bookmarks.adrのバックアップは無制限なので注意
  
  CmdLine := SessionsPath "\" BackupName
  SplitPath, CmdLine, , , , SessionName
  Result := "#FOLDER`n  NAME=[Session] " SessionName "`n`n"
  ResultBuf := Result
  
  Idx := 0
  BefGroupNum := 0
  His0Prefix :=
  Loop {
    Idx := RegExMatch(OSession, "\[(\d+)\][^\[]+group=(\d+)[^\[]+\[\1history url\][^\[]+count=(\d+)", $, Idx + 1)
    If !Idx
      Break
    WinNum := $1
    GroupNum := $2
    HisNum := $3 - 1
    HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
    HisUrl := GetHisUrl(OSession, WinNum, HisNum, Idx)
    
    if StackSW
      if (BefGroupNum != GroupNum) {
        if BefGroupNum
          Result .= "-`n`n"
        if GroupNum
          Result .= "#FOLDER`n  NAME=[Stack] " GroupNum "`n`n"
        BefGroupNum := GroupNum
      }
    
    If !HisReadSW {  ; タブ履歴を無視する場合
      Result .= "#URL`n  NAME=" HisTitle "`n  URL=" HisUrl "`n`n"
      Continue
    }
    
    StringLen, HisNumLen, HisNum
    
    If !HisNum {
      if His0PrefixSW
        His0Prefix := "[" ZeroSupply(HisNum, HisNumLen) "] "
      Result .= "#URL`n  NAME=" HisPrefix HisTitle "`n  URL=" HisUrl "`n`n"
      Continue
    }
    Result .= "#FOLDER`n  NAME=" HisTitle "`n`n#URL`n  NAME=[" ZeroSupply(HisNum, HisNumLen) "] " HisTitle "`n  URL=" HisUrl "`n`n"
    
    Loop, %HisNum% {
      HisNum--
      HisTitle := GetHisTitle(OSession, WinNum, HisNum, Idx)
      HisUrl := GetHisUrl(OSession, WinNum, HisNum, Idx)
      Result .= "#URL`n  NAME=[" ZeroSupply(HisNum, HisNumLen) "] " HisTitle "`n  URL=" HisUrl "`n`n"
    }
    Result .= "-`n`n"
  }
  
  If (ResultBuf == Result)
    return
  Result .= "-`n`n"
  
  If WriteTrgSW {
    FileRead, BMBuf, *t *P65001 %BookmarksPath%
    StringGetPos, Idx, BMBuf, #DELETED
    if !Idx {
      StringMid, BMBufP, BMBuf, 1, Idx
      StringMid, BMBufS, BMBuf, Idx + 1
      Result := BMBufP Result BMBufS
      FileDelete, %BookmarksPath%
    }
    FileAppend, %Result%, %BookmarksPath%, CP65001
  } Else {
    FileDelete, %CmdLine%.txt
    FileAppend, %Result%, %CmdLine%.txt, CP65001
  }
  
  If ACMoveSW {
    IfNotExist, %SessionsPath%\AutoConv\
      FileCreateDir, %SessionsPath%\AutoConv\
    FileMove, %CmdLine%, %SessionsPath%\AutoConv\%BackupName%
    If ErrorLevel
      MsgBox, 48, , 変換済みセッションの移動に失敗しました。`n%SessionsPath%\AutoConv\
  }
return

; --------- --------- --------- --------- ---------

GetHisTitle(OSession, WinNum, HisNum, Idx){
  RegExMatch(OSession, "\[" WinNum "history title\][\s\S]+?" HisNum "=(.*?)\r?\n", $)
  return $1
}

GetHisUrl(OSession, WinNum, HisNum, Idx){
  RegExMatch(OSession, "\[" WinNum "history url\][\s\S]+?" HisNum "=(.*?)\r?\n", $)
  return $1
}

ZeroSupply(Num, NumDigit){
  StringLen, NumLen, Num
  LoopNum := NumDigit - NumLen
  Loop, %LoopNum%
    Num := 0 Num
  return, Num
}


[PR]
by LordNoesis | 2016-02-05 18:50 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、標準出力を得る方法。

 新しいの

 AHKでCUIアプリの吐く標準出力を得る方法が分からんかったので調べたらフォーラムにあったのでメモ。

 日本語環境用にラスト1行だけ書き換えた。

; http://www.autohotkey.com/board/topic/15455-stdouttovar/page-8#entry540600

MsgBox % sOutput := StdoutToVar_CreateProcess("tasklist /s " A_ComputerName)

StdoutToVar_CreateProcess(sCmd, bStream = False, sDir = "", sInput = "") {
  DllCall("CreatePipe", "UintP", hStdInRd , "UintP", hStdInWr , "Uint", 0, "Uint", 0)
  DllCall("CreatePipe", "UintP", hStdOutRd, "UintP", hStdOutWr, "Uint", 0, "Uint", 0)
  DllCall("SetHandleInformation", "Uint", hStdInRd , "Uint", 1, "Uint", 1)
  DllCall("SetHandleInformation", "Uint", hStdOutWr, "Uint", 1, "Uint", 1)
  VarSetCapacity(pi, 16, 0)
  NumPut(VarSetCapacity(si, 68, 0), si)  ; size of si
  NumPut(0x100 , si, 44)      ; STARTF_USESTDHANDLES
  NumPut(hStdInRd , si, 56)    ; hStdInput
  NumPut(hStdOutWr, si, 60)    ; hStdOutput
  NumPut(hStdOutWr, si, 64)    ; hStdError
  If Not DllCall("CreateProcess", "Uint", 0, "Uint", &sCmd, "Uint", 0, "Uint", 0, "int", True, "Uint", 0x08000000, "Uint", 0, "Uint", sDir ? &sDir : 0, "Uint", &si, "Uint", &pi)  ; bInheritHandles and CREATE_NO_WINDOW
    ExitApp
  DllCall("CloseHandle", "Uint", NumGet(pi,0))
  DllCall("CloseHandle", "Uint", NumGet(pi,4))
  DllCall("CloseHandle", "Uint", hStdOutWr)
  DllCall("CloseHandle", "Uint", hStdInRd)
  If sInput <>
  DllCall("WriteFile", "Uint", hStdInWr, "Uint", &sInput, "Uint", StrLen(sInput), "UintP", nSize, "Uint", 0)
  DllCall("CloseHandle", "Uint", hStdInWr)
  bStream ? (bAlloc:=DllCall("AllocConsole"),hCon:=DllCall("CreateFile","str","CON","Uint",0x40000000,"Uint",bAlloc ? 0 : 3,"Uint",0,"Uint",3,"Uint",0,"Uint",0)) : ""
  VarSetCapacity(sTemp, nTemp:=bStream ? 64-nTrim:=1 : 4095)
  Loop
    If DllCall("ReadFile", "Uint", hStdOutRd, "Uint", &sTemp, "Uint", nTemp, "UintP", nSize:=0, "Uint", 0)&&nSize
    {
      NumPut(0,sTemp,nSize,"Uchar"), VarSetCapacity(sTemp,-1), sOutput.=sTemp
      If bStream&&hCon+1
        Loop
          If RegExMatch(sOutput, "[^\n]*\n", sTrim, nTrim)
            DllCall("WriteFile", "Uint", hCon, "Uint", &sTrim, "Uint", StrLen(sTrim), "UintP", nSize:=0, "Uint", 0)&&nSize ? nTrim+=nSize : ""
          Else Break
    }
    Else Break
  DllCall("CloseHandle", "Uint", hStdOutRd)
  bStream ? (DllCall("Sleep","Uint",1000),hCon+1 ? DllCall("CloseHandle","Uint",hCon) : "",bAlloc ? DllCall("FreeConsole") : "") : ""
  Return StrGet(&sOutput,"CP932")
}

 なんで探してたかって、es.exe(コマンドライン版Everything)をAHKから使いたかったんすよ。これでSearchResult := StdoutToVar_CreateProcess("es.exe 検索文字列")とかやれば超便利。

 例えば、以前書いたパスリストをX-Finderのクリップフォルダに変換するスクリプトと組み合わせるとか? テキスト介せばlist2xf.exeでも同じことできるけど。


[PR]
by lordnoesis | 2014-06-10 20:20 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、Sz7内のジャンプ移動してみた。

 axpathlist2.spiはとても便利なんだが、リストが長大になると探索が大変で、フォルダ分けされてればビューアのフォルダ移動機能で楽できるのになーと思ったので、AHKでそれっぽくがんばってみた。

 空行でパス群を区切ったSz7を用意し、MassiGraでAlt+Up/Downすれば、フォルダ移動みたいな感じで次/前のパス群までジャンプする。例によって、MassiGra以外にも応用できるはず。

 ただし、Sz7に記述されたパスのリンク切れなどによって、ファイル名に含まれる連番と、パスの記述順がズレるとジャンプもズレる。ビューア側からは有効パスの連番しかわからず、それを元にSz7を走査してアタリをつけているので。

;--------------------------------------------------------------------------------------
; MassiGra
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class TF811202_MassiGra_Main

; Sz7中の次/前のファイル群(空行区切り)までジャンプ

!Up::Sz7Jump(0)
!Down::Sz7Jump(1)

Sz7Jump(SW) {
  WinGet, WHwnd, ID
  WinGetTitle, WTitle, ahk_id %WHwnd%
  if !RegExMatch(WTitle, "i)^([^<]+\.sz\d+)\\([^<]+)\.[^<]+(?:\s+<.+)?$", $)
    return
  Sz7Path := $1
  ItemNum := $2
  
  FileRead, Sz7Buf, *t *P932 %Sz7Path%
  Sz7Buf := "`n`n" Sz7Buf
  
  if SW {  ; 次
    if !RegExMatch(Sz7Buf, "^(?:\n+[^\n]+){" ItemNum ",}?\n{2,}[^\n]+\.([^\n\.]+)", $)
      return
  } else {  ; 前
    if !RegExMatch(Sz7Buf, "^(?:\n+[^\n]+){0," ItemNum - 2 "}\n{2,}[^\n]+\.([^\n\.]+)", $)
      return
  }
  TxtBuf := $
  FileExt := $1
  
  ErrorLevel := 0
  while !ErrorLevel
    StringReplace, TxtBuf, TxtBuf, `n`n, `n, All
  
  StringReplace, TxtBuf, TxtBuf, `n, `n, UseErrorLevel
  DropFiles(WHwnd, Sz7Path "\" ZeroSup(ErrorLevel, 9) "." FileExt)
}



ZeroSup(Num, NumDigit) {
  RegExMatch(Num, "^0*+(\d*)$", $)
  StringLen, NumLen, $1
  LoopNum := NumDigit - NumLen
  Loop, %LoopNum%
    $1 := 0 $1
  return, $1
}


DropFiles(hwnd, files, ptX=0, ptY=0, fNC=False) {  ; AutoHotkey スレッド part11 >>332
  static char_type:= A_IsUnicode ? "UShort" : "UChar"
    , char_size := A_IsUnicode ? 2 : 1
    , isUnicode := A_IsUnicode ? 1 : 0
  files := RTrim(files, "`r`n`t ") . "`n`n"
  byte_length := StrLen(files) * char_size
  Loop, Parse, files
    If (A_LoopField = "`n")
      NumPut(0x00, files, (A_Index-1) * char_size, char_type)
  
  hDrop := DllCall("GlobalAlloc", "UInt", 0x42, "UInt",20 + byte_length, "Ptr")
  p := DllCall("GlobalLock", "Ptr", hDrop)
  NumPut(20 , p + 00, "Int") ; offset
  NumPut(ptX , p + 04, "Int") ; pt.x
  NumPut(ptY , p + 08, "Int") ; pt.y
  NumPut(fNC , p + 12, "Int") ; fNC
  NumPut(isUnicode, p + 16, "Int") ; fWide
  DllCall("RtlMoveMemory", "Ptr", p + 20, "Str", files, "UInt", byte_length)
  DllCall("GlobalUnlock", "Ptr", hDrop)
  PostMessage, WM_DROPFILES := 0x233, hDrop , 0, , ahk_id %hwnd%
  if ErrorLevel
    MsgBox, DropFiles Err %errorlevel%
}

 たぶん、問題ない(ジャンプ先検出の正規表現に辿り着いたのかなり偶然なのでry)。

 axpathlist2.spi(てかSz7)自体がフォルダ分けに対応してればさー。あと、ファイル名とか内臓Docで元のパスわかるようにするとかー、リンク切れはダミー画像とかー、Unicode対応とかー、別のSz7のインクルードとかー、ワイルドカードとかー、相対パスとかさー、などと好き勝手いってたら、相対パスにはとっくの昔に対応済みだったという恥ずかしエピソードが。


[PR]
by lordnoesis | 2014-02-26 20:00 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、メディアプレーヤーを目覚ましアラームに。

 快適な目覚めのためには、時間をかけて徐々に目覚める必要があり、それに音楽を使うというのは知られた方法だが、音量までタイマー操作できるハード/ソフトってそうなくね? てかAHKで操作すればよくね? というわけで書いた。

 ウチはサブのオーディオデバイスのみスピーカーに繋がっている構成なので、出力するオーディオデバイスが選択できて、かつシンプルなプレーヤーということでQonohaを使った。自由度それなりに書いたので、その辺は各自適当に。

;--------------------------------------------------------------------------------------
; Qonoha
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class QonohaPlayerMainWnd

F12::
  SetTimer, AAlarmRun, Off
  ;~ TipView()

  Loop {
    InputBox, AlarmTimeSet, AudioAlarm, アラーム時刻を24時間表記で入力してください`n例:午後1時5分 => 1305, , , 150
    if ErrorLevel
      return
    if RegExMatch(AlarmTimeSet, "([0-1][0-9]|2[0-3])([0-5][0-9])", $)
      break
  }
  AlarmH := $1
  AlarmM := $2

  AlarmTime := A_Now
  if (A_Hour > AlarmH) || (A_Hour == AlarmH && A_Min >= AlarmM) {
    AlarmTxt := "明日"
    EnvAdd, AlarmTime, 1, D
  } else {
    AlarmTxt := "本日"
  }

  FormatTime, AlarmTime, %AlarmTime%, yyyyMMdd'%AlarmH%%AlarmM%00'

  FormatTime, AlarmTxt, %AlarmTime%, %AlarmTxt%HH時mm分
  MsgBox, 262177, AudioAlarm, %AlarmTxt% にセットします。
  IfMsgBox, Cancel
    return

  FormatTime, AlarmTxt, %AlarmTime%, アラーム日時:dd日HH時mm分

  EnvSub, AlarmTime, , S
  if !AlarmTime {
    MsgBox, 262160, AudioAlarm, %AlarmTxt%を過ぎています。
    return
  }

  ;~ TipView(AlarmTxt, AlarmTime "000", 0, 0)
  SetTimer, AAlarmRun, -%AlarmTime%000
return

AAlarmRun:
  AudioFilePath := "C:\Users\Public\Music\Sample Music\Sleep Away.mp3"  ; 再生したいファイルのパス。
  SplitPath, AudioFilePath, AudioFileName

  PlayerPath := "C:\Qonoha\Qonoha.exe"
  PlayerTitle := AudioFileName " ahk_class QonohaPlayerMainWnd"
  VolUpKey := "Up"  ; 音量を上げるキー
  VolDnKey := "Down"  ; 音量を下げるキー

  VolMax := 25  ; 音量の最大値(VolUpKeyを何回叩くか)
  VolMaxPeriod := 3600000  ; 音量が最大になるまでにかかる時間(ミリ秒)

  Run, "%PlayerPath%" "%AudioFilePath%"
  WinWait, %PlayerTitle%
  Send, {%VolDnKey% %VolMax%}  ; 音量をゼロに

  VolUpWait := VolMaxPeriod / VolMax
  MACnt := 0
  SetTimer, AAlarmSnooze, %VolUpWait%

  MsgBox, 262208, AudioAlarm, %AlarmTxt% になりました。`n`n%AudioFileName%
  SetTimer, AAlarmSnooze, Off
  WinClose, %PlayerTitle%
return

AAlarmSnooze:
  MACnt++
  WinActivate, %PlayerTitle%
  Send, {%VolUpKey%}
  WinActivate, AudioAlarm ahk_class #32770
  if (VolMax <= MACnt)
    SetTimer, AAlarmSnooze, Off
return

 セット後にアラーム時刻を表示したいなら、コメントアウトしてあるTipView()を使う。

;--------------------------------------------------------------------------------------
; TipView.ahk
;--------------------------------------------------------------------------------------

TipView(TextBuf = "", Timer = 3000, X = "", Y = "", SW = 0) {
  if SW
    CoordMode, ToolTip

  ToolTip, %TextBuf%, X, Y
  if !Timer
    Timer := "Off"
  SetTimer, TipClose, %Timer%
}

TipClose:
  SetTimer, TipClose, Off
  ToolTip
return


[PR]
by lordnoesis | 2014-02-16 22:15 | テクノロジ | Trackback | Comments(0)

AutoHotKey_Lで、パスリストをX-Finderのクリップフォルダに変換。Ver.1.2

 先々週書いたEverythingの検索結果をX-Finderで開くシリーズの最新版なんだけど、関数をEverything以外でも使えるようにしてみた。これで\n区切りのパスリストがあれば、なんでもサムネで確認できるよ!やったねry
 もっと機能追加してからPostしようと思って大していじらず1週間たってしまったのでエターナる前にPost。

 使用例は相変わらずEverything。検索結果の任意のアイテムを選択状態にしてF11を打鍵すると、X-Finderでクリップフォルダとして開く。Ctrl+F11なら、前回のクリップフォルダに追加。

 Everything以外は各自勝手に。InputBoxでIni名指定できたらブックマーク的に使えて便利かも。

 デフォルトのIni名にプレフィックスつけたんで、X-Finderのクリップフォルダ設定に;Extra:%X-Finder%CF_*.iniと加えとくと便利。

;--------------------------------------------------------------------------------------
; Everything
;--------------------------------------------------------------------------------------
#IfWinActive ahk_class ahk_class EVERYTHING

F11::
  #ClipboardTimeout 200000
  
  ClipWaitNull()
  Send, ^c
  ClipWait, 3
  if !ErrorLevel {
    CFPath := Path2ClipFld(Clipboard, "CF_Everything.ini")
    Run, "C:\X-Finder\XF.exe" "Extra:%CFPath%"  ; X-Finderのフルパス。
  }
  ClipWaitRestore()
return

^F11::
  #ClipboardTimeout 200000
  
  ClipWaitNull()
  Send, ^c
  ClipWait, 3
  if !ErrorLevel {
    CFPath := Path2ClipFld(Clipboard, "CF_Everything.ini", 1)
    Run, "C:\X-Finder\XF.exe" "Extra:%CFPath%"  ; X-Finderのフルパス。
  }
  ClipWaitRestore()
return


Path2ClipFld(PathList, ClipFldPath = 0, AddSW = 0) {  ; Ver.1.2
  XFPath := "C:\X-Finder\"  ; パスリストのデフォルト保存先。
  if ClipFldPath {
    IfNotInString, ClipFldPath, :\
      ClipFldPath := XFPath ClipFldPath
  } else {
    ClipFldPath := XFPath "CF_.ini"
  }
  
  StringReplace, PathList, PathList, `n, `n, UseErrorLevel
  PathNum := ErrorLevel + 1
  
  if AddSW
    IniRead, IniCnt, %ClipFldPath%, X-Finder, Count, 0
  else
    IniCnt := 0
  
  if !IniCnt
    ClipFldBuf := "[X-Finder]`nCount=" PathNum
  
  Loop, Parse, PathList, `n, `r
  {
    if ("\" == SubStr(A_LoopField, 0))
      ItemPath := SubStr(A_LoopField, 1, -1)
    else
      ItemPath := A_LoopField
    
    SplitPath, ItemPath, ItemName
    ItemNum := A_Index + IniCnt - 1
    
    ClipFldBuf .= "`nName" ItemNum "=" Str2RefStr(ItemName) "`nPath" ItemNum "=""" Str2RefStr(ItemPath) """`nType" ItemNum "=1"
  }
  
  if AddSW {
    IniCnt += PathNum
    IniWrite, %IniCnt%, %ClipFldPath%, X-Finder, Count
  } else {
    FileDelete, %ClipFldPath%
  }
  
  FileAppend, %ClipFldBuf%, %ClipFldPath%, CP932
  return, ClipFldPath
}

Str2RefStr(StrBuf) {
  Transform, StrBuf, HTML, %StrBuf%, 2
  SetFormat, Integer, H
  Loop {
    if !RegExMatch(StrBuf, "&#(\d+);", $)
      break
    
    TipNum := 0 + $1
    StringTrimLeft, TipNum, TipNum, 2
    if (0 != TipLen := 4 - StrLen(TipNum))
      Loop, %TipLen%
        TipNum := "0" + TipNum
    
    StringReplace, StrBuf, StrBuf, &#%$1%;, &#x%TipNum%;, All
  }
  SetFormat, Integer, D
  StringReplace, StrBuf, StrBuf, &, &, All
  return, StrBuf
}


ClipWaitNull(SW = 1) {
  if SW {
    global CBBackup
    CBBackup := ClipboardAll
  }
  
  Clipboard :=
  while Clipboard
    Sleep, 100
}

ClipWaitRestore() {
  global CBBackup
  
  ClipWaitNull(0)
  Clipboard := CBBackup
  ClipWait
}

 先人の作った「list2xf.exe」との違いは――AHKで応用しやすいってのと、Unicode文字対応ってあたりかなー。

 Everything Ver.1.4は普通のListViewになってたので、Clipboard経由せずControlGet, PathList, List, Selected, SysListView321, Aで取得して加工してもよい。



おまけ。
[PR]
by lordnoesis | 2014-01-17 19:25 | テクノロジ | Trackback(1) | Comments(0)
ブログトップ | ファンになる