自動化ツール/AutoHotkey

Last-modified: 2019-02-25 (月) 19:49:34

Mery用構文ファイル

MSBuild用プロジェクトファイルのテンプレート

.ahkファイルをExe化する。

<?xml version="1.0" encoding="utf-8" ?>
<!--
  MSBuild用プロジェクトファイルの例
    同一フォルダにある.ahkファイルをExe化する
    このプロジェクトファイルは.ahkファイルと同じフォルダにあること
-->
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!-- Ahk2Exe.exeのフルパス -->
  <PropertyGroup>
    <AHK2EXE>$(ProgramFiles)\AutoHotkey\Compiler\Ahk2Exe.exe</AHK2EXE>
  </PropertyGroup>
  <!-- ソースファイル名;foo.ahk→foo.exeとする場合 -->
  <ItemGroup>
    <SOURCE_FILES Include="foo.ahk" />
    <!--
    <SOURCE_FILES Include="foo2.ahk" />
    <SOURCE_FILES Include="foo3.ahk" />
      :
    -->
  </ItemGroup>
  <!-- ソースファイル名;bar.ahk→baz.exeとする場合 -->
  <ItemGroup>
    <SOURCE_FILES2 Include="bar.ahk">
        <EXE_FILE>baz.exe</EXE_FILE>
    </SOURCE_FILES2>
    <!--
    <SOURCE_FILES2 Include="bar2.ahk">
        <EXE_FILE>baz2.exe</EXE_FILE>
    </SOURCE_FILES2>
    <SOURCE_FILES2 Include="bar3.ahk">
        <EXE_FILE>baz3.exe</EXE_FILE>
    </SOURCE_FILES2>
      :
    -->
  </ItemGroup>
  <!-- Buildターゲットからビルド後に呼び出されるターゲット -->
  <Target Name="Build" Inputs="@(SOURCE_FILES);@(SOURCE_FILES2)" Outputs="@(SOURCE_FILES->'%(Filename).exe');%(SOURCE_FILES2.EXE_FILE)">
    <Exec Command="%22$(AHK2EXE)%22 /in %22%(SOURCE_FILES.Identity)%22" WorkingDirectory="$(MSBuildProjectDirectory)" Condition="'@(SOURCE_FILES->Count())' &gt; 0" />
    <Exec Command="%22$(AHK2EXE)%22 /in %22@(SOURCE_FILES2)%22 /out %22%(EXE_FILE)%22" WorkingDirectory="$(MSBuildProjectDirectory)" Condition="'@(SOURCE_FILES2->Count())' &gt; 0" />
  </Target>
</Project>

コマンドプロンプト:Ctrl+Vで貼り付け

NYAOSでも動作する。

#SingleInstance
#IfWinActive ahk_class ConsoleWindowClass
^v::SendInput {Raw}%Clipboard%
#IfWinActive

今日の日付をyyyymmdd形式で入力

::td::
  Send,%A_YYYY%%A_MM%%A_DD%
  Return

平仮名・カタカナ変換など

LCMAP_BYTEREV             := 0x00000800	; Windows NT のみ : バイト順序を反転します。たとえば 0x3450 と 0x4822 を渡すと、結果は 0x5034 と 0x2248 になります。
LCMAP_FULLWIDTH           := 0x00800000	; 全角文字にします(適用される場合)。
LCMAP_HALFWIDTH           := 0x00400000	; 半角文字にします(適用される場合)。
LCMAP_HIRAGANA            := 0x00100000	; ひらがなにします。
LCMAP_KATAKANA            := 0x00200000	; カタカナにします。
LCMAP_LINGUISTIC_CASING   := 0x01000000	; 大文字と小文字の区別に、ファイルシステムの規則(既定値)ではなく、言語上の規則を使います。LCMAP_LOWERCASE、または LCMAP_UPPERCASE とのみ組み合わせて使えます。
LCMAP_LOWERCASE           := 0x00000100	; 小文字を使います。
LCMAP_SIMPLIFIED_CHINESE  := 0x02000000	; 中国語の簡体字を繁体字にマップします。
LCMAP_SORTKEY             := 0x00000400	; 正規化されたワイド文字並び替えキーを作成します。
LCMAP_TRADITIONAL_CHINESE := 0x04000000	; 中国語の繁体字を簡体字にマップします。
LCMAP_UPPERCASE           := 0x00000200	; 大文字を使います。
NORM_IGNORECASE           := 0x00000001	; 大文字と小文字を区別しません。
NORM_IGNOREKANATYPE       := 0x00010000	; ひらがなとカタカナを区別しません。ひらがなとカタカナを同じと見なします。
NORM_IGNORENONSPACE       := 0x00000002	; 送りなし文字を無視します。このフラグをセットすると、日本語アクセント文字も削除されます。
NORM_IGNORESYMBOLS        := 0x00000004	; 記号を無視します。
NORM_IGNOREWIDTH          := 0x00020000	; シングルバイト文字と、ダブルバイトの同じ文字とを区別しません。
SORT_STRINGSORT           := 0x00001000	; 区切り記号を記号と同じものとして扱います。
flags := LCMAP_HALFWIDTH + LCMAP_KATAKANA
word := "こんにちは。"
length := 256
VarSetCapacity(output, length)
DllCall("kernel32\LCMapString", "UInt", DllCall("kernel32\GetUserDefaultLCID"), "UInt", flags, "WStr", word, "Int", -1, "WStr", output, "Int", length)
MsgBox,%output%
VarSetCapacity(output, -1)

音声合成

Windows 7の場合、Microsoft Speech Platform 11以降とHaruka 日本語のインストールが必要。

objSp := ComObjCreate("Speech.SpVoice")  ; 通常は Speech.SpVoice でOK
; objSp := ComObjCreate("SAPI.SpVoice")  ; SAPI5対応日本語音声合成エンジンを使用する場合
objSp.Speak("庭には二羽ニワトリがいる。")

レーベンシュタイン距離を求める

; https://nayose.net/blog/address/246/ をベタ移植
lsDist(baseText, tryText)
{
    If baseText = tryText
        Return 0
    bl := StrLen(baseText)
    tl := StrLen(tryText)
    If bl = 0
        Return tl
    If tl = 0 Then
        Return bl
    matrix := []
    Loop,% bl+1
        matrix.push([A_Index-1])
    Loop,% tl+1
        matrix[1, A_Index] := A_Index - 1
    Loop,%bl%
    {
        i := A_Index + 1
        Loop,%tl%
        {
            j := A_Index + 1
            If SubStr(baseText, i, 1) = SubStr(tryText, j, 1)
                cost := 0
            Else
                cost := 1
            matrix[i, j] := Min(matrix[i-1, j]+1, matrix[i, j-1]+1, matrix[i-1, j-1]+cost)
        }
    }
    Return matrix[bl+1, tl+1]
}

Excelワークシートに対してSQLで問い合わせ

1行目は見出し(列名)であること。

; Excelワークシートに対してSQLで問い合わせ(ADO)
; 結果はクリップボードにコピーする
; 要2007 Office system ドライバ: データ接続コンポーネント
; インストールされていない場合は https://www.microsoft.com/ja-jp/download/details.aspx?id=23734 からDL
#SingleInstance
DefaultQuery := "
(
SELECT
    COUNT(*)
FROM
    [Sheet1$]
;
)"
EM_SETCUEBANNER := 0x1501
Gui,New,,ExcelワークシートでSQL実行
Gui,Font,,MS UI Gothic
Gui,Add,Text,,SQL文(&S):
Gui,Add,Edit,r15 vquery w340 xs+10 HwndqueryH,% DefaultQuery
DllCall("SendMessageW", "Ptr", queryH, "UInt", EM_SETCUEBANNER, "Ptr", True, "WStr", "※入力必須")
Gui,Add,Button,gOnExecute xs,実行(&X)
Gui,Show
Return
OnExecute:
    Gui,Submit,NoHide
    If query =
    {
        MsgBox,SQL文が入力されていません
        Return
    }
    FileSelectFile,file,33,,ファイルを開く,Excelファイル(*.xlsx;*.xls)
    If file =
        Return
    ;adOpenForwardOnly := 0
    ;adOpenKeyset := 1
    ;adLockReadOnly := 1
    adUseClient := 3
    objConnection := ComObjCreate("ADODB.Connection")
    Try {
        objConnection.Open("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=""" . file . """;Extended Properties=""Excel 12.0;HDR=YES;IMEX=1;"";")
    } Catch e {
        MsgBox,% "Connectionオブジェクトの取得に失敗しました: " . e.Message . "`n中断します"
        ExitApp
    }
    objConnection.CursorLocation := adUseClient
    objRecordset := ComObjCreate("ADODB.Recordset")
    Try {
        ;objRecordset.Open(query, objConnection, adOpenForwardOnly, adLockReadOnly)
        objRecordset.Open(query, objConnection)
    } Catch e {
        MsgBox,% "クエリに失敗しました。恐らくSQL文が間違っています: " . e.Message
        Return
    }
    report =
    If (!objRecordset.EOF And objRecordset.Fields.Count > 0)
    {
        ; 見出しを作成
        report .= objRecordset.Fields(0).Name
        Loop,% objRecordset.Fields.Count - 1
        {
            report .= "`t" . objRecordset.Fields(A_Index).Name
        }
        report .= "`r`n"
        ; 結果を作成
        While !objRecordset.EOF
        {
            report .= objRecordset.Fields(0).Value
            Loop,% objRecordset.Fields.Count - 1
            {
                report .= "`t" . objRecordset.Fields(A_Index).Value
            }
            report .= "`r`n"
            objRecordset.MoveNext
        }
        Clipboard := report
    }
    objRecordset.Close()
    objConnection.Close()
    MsgBox,正常終了しました。結果はクリップボードにコピーされます
Return
GuiClose:
ExitApp

Excelのアクティブセルを始点としてCSVファイルをインポートする

; セルの文字列が 0 で始まる場合は表示形式を文字列にする
xlCalculationAutomatic := -4105
xlCalculationManual := -4135
Try {
    objExcel := ComObjActive("Excel.Application")
} Catch e {
    MsgBox,Excelが起動していません。中断します
    Return
}
If (objExcel.Workbooks.Count < 1) {
    MsgBox,予め既存または新規のExcelブックを開き、インポート先シートをアクティブにしておいてください。中断します
    Return
}
row := objExcel.Selection.Row
col := objExcel.Selection.Column
FileSelectFile,csvfile,1,,CSVファイルを開く,CSV file (*.csv;*.txt)
If csvfile =
    ExitApp
objExcel.Calculation := xlCalculationManual
objExcel.ScreenUpdating := False
Loop,Read,%csvfile%
{
    y := A_Index
    Loop,Parse,A_LoopReadLine,CSV
    {
        If (StrLen(A_LoopField) > 1 && SubStr(A_LoopField,1,1) == "0")
            objExcel.ActiveSheet.Cells(row, col).Offset(y-1, A_Index-1).NumberFormatLocal := "@"
        objExcel.ActiveSheet.Cells(row, col).Offset(y-1, A_Index-1).Value := A_LoopField
    }
}
objExcel.ScreenUpdating := True
objExcel.Calculation := xlCalculationAutomatic

Outlookで新規メールアイテムを作成

olMailItem := 0
; 送信先メールアドレス:複数指定時は ; で区切る
toAddress := "送り先メールアドレス"
ccAddress := ""
bccAddress := ""
; サブジェクト
subject := "TEST"
; %APPDATA%\Microsoft\Signatures\ フォルダ下にある署名ファイル(.txt)
signFile := "署名.txt"
message := "
(
:(ここにメール文面)
)"
Try
{
  objOutlook := ComObjActive("Outlook.Application")
}
Catch e
{
  MsgBox,4,,% "Outlook が起動していません: " . e.Message . "`n当スクリプトをリロードしますか?"
  IfMsgBox,Yes
    Reload
  ExitApp
}
objMailItem := objOutlook.CreateItem(olMailItem)
If StrLen(toAddress) > 0
  objMailItem.To := toAddress
If StrLen(ccAddress) > 0
  objMailItem.Cc := ccAddress
If StrLen(bccAddress) > 0
  objMailItem.Bcc := bccAddress
objMailItem.Subject := subject
objMailItem.Body := message
If StrLen(signFile) > 0
  objMailItem.Body .= "`n" . GetSignatures(signFile)
objMailItem.Display(False)
GetSignatures(file)
{
  FileRead,result,% A_AppData . "\Microsoft\Signatures\" . file
  return result
}

Outlookのメール着信を監視

#Persistent
olMail := 43  ; MailItemオブジェクト
Try
{
  objOutlook := ComObjActive("Outlook.Application")
}
Catch e
{
  MsgBox,4,,% "Outlook が起動していません: " . e.Message . "`nスクリプトをリロードしますか?"
  IfMsgBox,Yes
    Reload
  ExitApp
}
ComObjConnect(objOutlook, "OL_")
OL_NewMailEx(entryIdCollection) {
  global objOutlook
  global olMail
  PR_SENT_REPRESENTING_EMAIL_ADDRESS := "http://schemas.microsoft.com/mapi/proptag/0x0065001e"  ; FromがMLの場合、元々の差出人E-mailアドレス
  PR_SENT_REPRESENTING_NAME := "http://schemas.microsoft.com/mapi/proptag/0x0042001e"  ; 同、表示名(E-mailアドレスの場合も)
  ; MLの場合、SenderNameやSenderEmailAddressプロパティでは元々の差出人が判らない
  arrEntryId := StrSplit(entryIdCollection, ",")
  Loop % arrEntryId.MaxIndex()
  {
    objMailItem := objOutlook.Session.GetItemFromID(arrEntryId[A_Index])
    If (objMailItem.Class <> olMail) {
      Continue
    }
    ; 以下、ニーズによって処理が変わる。ここではクリップボードにメールアドレスなどコピー
    Clipboard = % "Subject=" . objMailItem.Subject
        . "`nSenderEmailAddress=" . objMailItem.SenderEmailAddress
        . "`nSenderName=" . objMailItem.SenderName
        . "`nCc=" . objMailItem.Cc
    ; 文面は objMailItem.Body
    ; 添付ファイルは objMailItem.Attachments
    ; MLなら objMailItem.PropertyAccessor.GetProperty(PR_SENT_REPRESENTING_EMAIL_ADDRESS)
    ; または objMailItem.PropertyAccessor.GetProperty(PR_SENT_REPRESENTING_NAME)
  }
}
OL_ItemSend(objMailItem, ByRef isCancel) {
  global olMail
  If (objMailItem.Class <> olMail) {
    Return
  }
  ; 以下、ニーズによって処理が変わる
  MsgBox,48,Outlook,% objMailItem.To . " へメール送信",1
  ; 送信をキャンセルする場合は isCancel = True に
}
OL_Quit() {
  MsgBox,48,Outlook,Good bye,1
  ExitApp
}

Outlookのメール添付ファイルをマイドキュメントに保存

#SingleInstance
#IfWinActive ahk_exe OUTLOOK.EXE
; Shift+F8: 添付ファイルをマイドキュメントに保存
+f8::
  olMail := 43  ; MailItemオブジェクト
  objOutlook := ComObjActive("Outlook.Application")
  If (ComObjType(objOutlook.ActiveWindow, "Name") = "_Inspector")
    objMailItem := objOutlook.ActiveInspector.CurrentItem
  Else If (ComObjType(objOutlook.ActiveWindow, "Name") = "_Explorer" And objOutlook.ActiveExplorer.Selection.Count == 1)
    objMailItem := objOutlook.ActiveExplorer.Selection.Item(1)
  Else
    Return
  If (objMailItem.Class == olMail)
  {
    Loop % objMailItem.Attachments.Count
    {
      MsgBox,3,確認,% "【" . objMailItem.Attachments(A_Index).FileName . "】を保存しますか?"
      IfMsgBox,Yes
        objMailItem.Attachments(A_Index).SaveAsFile(A_MyDocuments . "\" . objMailItem.Attachments(A_Index).FileName)
      Else IfMsgBox,Cancel
        Break
    }
  }
  Return
#IfWinActive

sqlite3.dll利用

#Include Class_SQLiteDB.ahk  ; ←https://github.com/AHK-just-me/Class_SQLiteDBからDL
db := new SQLiteDB
MsgBox,% db.Version
db.OpenDB(A_ScriptDir . "\test.db")
db.Exec("CREATE TABLE list(id INTEGER, title TEXT);")
sqlbase := "INSERT INTO list VALUES(#, 'test#');"
Loop,10
{
  StringReplace,sql,sqlbase,#,%A_Index%,All
  sqls .= sql
}
db.Exec("BEGIN TRANSACTION;")
db.Exec(sqls)
db.Exec("COMMIT TRANSACTION;")
db.GetTable("SELECT * FROM list WHERE id > 5;", tbl)
MsgBox,% tbl.ColumnNames[1] . ": " . tbl.ColumnNames[2]
Loop,% tbl.RowCount
{
  tbl.Next(r)
  MsgBox,% r[1] . ": " . r[2]
}
db.CloseDB()

nMail.dll利用

; nMail.dllを使ったメール送信(nMail.dllはhttp://www.nanshiki.co.jp/からDL)
NULL := 0
DllCall("nMail\NMailInitializeWinSock")
;MsgBox,% "NMailGetVersion = " . DllCall("nMail\NMailGetVersion")
smtp := "SMTPサーバ名"
to := "送信先メールアドレス"
cc := NULL
bcc := NULL
from := "送信元メールアドレス"
subject := "サブジェクト"
body := "本文"
header := NULL
path := NULL
flag := 0
port := 25
MsgBox,% "NMailSmtpSendMailPortNoW = " . DllCall("nMail\NMailSmtpSendMailPortNoW", "Str", smtp, "Str", to, ArgType(cc), cc, ArgType(bcc), bcc, "Str", from, "Str", subject, "Str", body, ArgType(header), header, ArgType(path), path, "Int", flag, "Int", port)
DllCall("nMail\NMailEndWinSock")
ArgType(arg)
{
  Return arg ? "Str" : "Int"
}

外人4コマジェネレータ

  • filegaijin4.zip…要ImageMagick 7.x(ImageMagickObjectの追加インストールが必要)。動作実績はWindows 7(x86)。肖像権とか侵害していそうだけど

DBテーブル作成スクリプト

  • filedbtable.zip… Excelのアクティブシートにある表(1列目が見出し、2列目以降がデータ)をSQLiteデータベーステーブルに変換する。結合セルがある表は処理できない。非表示行・非表示列も読み込む。要Class_SQLiteDB.ahkおよびsqlite3.dll