- Mery用構文ファイル
- MSBuild用プロジェクトファイルのテンプレート
- IExpressで実行形式ファイルを作る(UWSCフリー版)
- Call文で特殊変数を使う
- 配列を関数の戻り値にする
- 配列を引数にする
- 関連付けられたアプリケーションで開く
- 環境変数の取得
- name="submit" となっているボタンを押す
- For文のカウンタ変数はループ中に変更しないほうが良い
- Token()で改行を区切り文字にする
- スクリプト自身の実行を一時停止する
- レーベンシュタイン距離を求める
- フォーム内のエレメントのNameやIdをCSVファイルに出力
- Excelワークシートに対してSQLで問い合わせ
- Outlookで新規メールアイテムを作成
- Outlookのメール着信を監視
- nMail.dll利用
- 動作記録用Meryマクロ
- ランチメニュ向け
- その他
Mery用構文ファイル
Mery同梱の構文ファイルがちょっと使いにくかったので独自に作成したもの。
MSBuild用プロジェクトファイルのテンプレート
.uwsファイルをExe化する(Pro版)。
<?xml version="1.0" encoding="utf-8" ?> <!-- MSBuild用プロジェクトファイルの例 同一フォルダにある.uwsファイルをExe化する このプロジェクトファイルは.uwsファイルと同じフォルダにあること --> <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Uws2Exe.exeのフルパスとオプションの定義 --> <PropertyGroup> <UWS2EXE>$(MSBuildProgramFiles32)\UWSC\Uws2Exe.exe</UWS2EXE> <OPTIONS>/ME</OPTIONS> </PropertyGroup>
<!-- ソースファイル名 --> <ItemGroup> <SOURCE_FILES Include="foo.uws" /> <!-- <SOURCE_FILES Include="bar.uws" /> <SOURCE_FILES Include="baz.uws" /> : --> </ItemGroup>
<!-- Buildターゲットからビルド後に呼び出されるターゲット --> <Target Name="Build" Inputs="@(SOURCE_FILES)" Outputs="@(SOURCE_FILES->'%(Filename).exe')"> <Exec Command="%22$(UWS2EXE)%22 $(OPTIONS) %22%(SOURCE_FILES.Identity)%22" WorkingDirectory="$(MSBuildProjectDirectory)" /> </Target>
</Project>
IExpressで実行形式ファイルを作る(UWSCフリー版)
※UWSC Free版の二次配布は認められていないので、あくまで個人的な利用に留められたい。
同梱サンプルスクリプトGruGru.uwsを実行する.exeファイルは以下の手順で作成可能。なお、Pro版で作成した.exeファイルと違い、細かい制限などあると思うが詳しくテストしていないので注意。*1
- パッケージタイトル
- sample*2
- パッケージファイル(.exeファイル)名
- GruGru.exe
- .sedファイル名
- GruGru.sed
- コマンドプロンプトや「ファイル名を指定して実行」などから iexpress.exe を実行しIExpressのウィザードを起動
- [Create new SelfExtraction Directive file.]を選択して[次へ]
- [Extract files and run an installation command]を選択して[次へ]
- パッケージタイトルに sample と入力して[次へ]
- [No prompt.]を選択して[次へ]
- [Do not display a license.]を選択して[次へ]
- [Add]をクリックし、ファイルオープンダイアログボックスから UWSC.exe とスクリプトファイル(.uws)など動作に必要なファイルを選択(複数選択可)し、全て登録し終えたら[次へ]
- 今回の例では UWSC.exe とGruGru.uws を選択すれば動作する
- [Install Program]に UWSC.exe GruGru.uws と入力、[Post Install Command]は <None> のままにして[次へ]
- スクリプトファイル名に半角空白が含まれる場合、スクリプトファイル名を半角ダブルクォーテーションで囲む必要がある
- [Default (recommanded)]を選択して[次へ]
- [No message.]を選択して[次へ]
- [Browse]をクリックしてファイルセーブダイアログボックスから GruGru.exe の保存先を入力、[Store files using Long File Name inside Package]をチェック(確認ダイアログボックスが開くので[はい]で閉じる)して[次へ]
- スクリプトファイル名が8.3形式なら[Store files using Long File Name inside Package]のチェックは不要。8.3形式の意味が判らないならチェックしておけば間違いない
- [No restart]を選択して[次へ]
- 今までの設定を .sed ファイルに保存するなら[Save SelfExtraction Directive (SED) file:]を、保存しなくて良いなら[Don't save.]選択して[次へ]
- デフォルトではパッケージファイルと同じフォルダに.sedファイルが作られる
- [次へ]でパッケージファイル生成
- [完了]で IExpress を終了
設定を .sed ファイルに保存した場合、次回からパッケージファイルの作成手順が短縮できる。
- コマンドプロンプトや「ファイル名を指定して実行」などから iexpress.exe を実行
- [Open existing SelfExtraction Directive file:]で .sed ファイルを選択して[次へ]
- [Create Package.]を選択して[次へ]
- [次へ]でパッケージファイル生成
- [完了]で IExpress を終了
またコマンドラインから iexpress /N /Q /M GruGru.sed と実行すれば直ちにパッケージファイルが作られる。
Call文で特殊変数を使う
Call GET_CUR_DIR + "\Lib.uws" Call GET_CUR_DIR + "\Func.uws(<#DBL>Foo<#DBL>, 100)" // リテラルなら引数も渡せる
ローカル変数/グローバル変数だとエラーだが特殊変数(ディレクトリ)なら使える。
配列を関数の戻り値にする
Dim ary = RtnArray() // Dimを省略してもエラーにならない For i = 0 To Length(ary) - 1 Print ary[i] Next
Function RtnArray() Result = SafeArray(0, 3 - 1) // 空配列を返すには SafeArray(0, -1) とすれば Length() が 0 を返す Result[0] = "Aaa" Result[1] = "Bbb" Result[2] = "Ccc" FEnd
引数で返すならVarを付けるだけ。
Procedure RtnArray(Var a[]) a[0] = "aaa" a[1] = "bbb" a[2] = "ccc" FEnd
配列を引数にする
// ↓どちらの書き方でも通る Dim x[5][10] Dim y[10, 5]
x[1][1] = 100 y[2, 2] = 50
Foo(x)
// Length()だとサイズが、Resize()だと上限値が返る;これで二次元配列の大きさがわかる Procedure Foo(a[][]) Print Length(a) // 6 Print Resize(a) // 5 Print Length(a[1]) // 11 Print Resize(a[1]) // 10 FEnd
関連付けられたアプリケーションで開く
ファイルまたはショートカット(.lnk)を関連付けられたアプリケーションで開くには DosCmd("<#DBL>filepath<#DBL>") または PowerShell("<#DBL>filepath<#DBL>") を使う。
環境変数の取得
特定の環境変数を得るには ExpandEnvironmentStrings() メソッドか DosCmd("echo %environname%") を使う。
// My Documentsフォルダのパスを得る objShell = CreateOleObj("WScript.Shell") myDoc = objShell.ExpandEnvironmentStrings("%USERPROFILE%") + "\Documents"
全て得るなら DosCmd("set") かWScript.ShellオブジェクトのEnvironmentプロパティを使って戻り値を加工する。
// 全環境変数を連想配列にまとめる HashTbl dic GetEnvHash(dic) For i = 0 To Length(dic) - 1 Print dic[i, HASH_KEY] + " -> " + dic[i, HASH_VAL] Next
// 連想配列は戻り値には使えないようだが引数なら渡せる Procedure GetEnvHash(Var dic[]) lines = Split(DosCmd("set"), "<#CR>", TRUE) For i = 0 To Length(lines) - 1 l = BetweenStr(lines[i], "", "=") r = BetweenStr(lines[i], "=", "") dic[l] = r Next FEnd
// Environmentプロパティ版:値に%windir%など変数名が混じっていて使いにくい Procedure GetEnvHash2(Var dic[], type = "") objShell = CreateOLEObj("WScript.Shell") Select type Case "USER", "SYSTEM" objEnviron = objShell.Environment(type) Default objEnviron = objShell.Environment SelEnd For i In objEnviron l = BetweenStr(i, "", "=") r = BetweenStr(i, "=", "") dic[l] = r Next FEnd
name="submit" となっているボタンを押す
name="submit" となっているボタンはIESetData()でSUBMITできないことがある模様。
IESetData(objIE, TRUE, "submit", "送信") // これだと上手く動作しない場合がある objIE.Document.Forms[n].Submit() // これか objIE.Document.Forms[n].Submit.Click() // これのどちらかで対応 objIE.Document.Forms[n].Elements[m].Click() // これでもOK
For文のカウンタ変数はループ中に変更しないほうが良い
For i = 0 To 5 - 1 If i = 2 Then i = 3 Print i // 0, 1, 3, 3, 4 と出力される(0, 1, 3, 4 とはならない) Next
Token()で改行を区切り文字にする
// クリップボードのテキストを改行で区切る(空行はスキップ) // クリップボード中に <#CR> という文字列があると改行と見なされ区切られる sep = Chr(13) + Chr(10) // CR+LF str = GetStr(0) line = Token(sep, str, TRUE, TRUE) While (Length(str) > 0) MsgBox("行: " + line) line = Token(sep, str, TRUE, TRUE) WEnd
改行で区切るなら Split(GetStr(0), "<#CR>") で配列にしてしまう方が扱いやすい。
スクリプト自身の実行を一時停止する
Alt+F1(UWSCのデフォルト設定)で再開する。「読込み」で.uwsスクリプトを開き、「再生」で実行した場合のみ動作する模様(.exe版や関連付けで実行した.uwsスクリプトだとうまく動作しない)。
id = GetId(GET_THISUWSC_WIN) MsgBox("一時停止します") ScKey(id, VK_ALT, VK_F1) MsgBox("一時停止しました")
レーベンシュタイン距離を求める
大文字小文字を比較する場合は Option SAMESTR を宣言する。
// https://nayose.net/blog/address/246/ をベタ移植 Function lsDist(baseText, tryText) Result = 0 If baseText = tryText Then Exit
bl = Length(baseText) tl = Length(tryText) If bl = 0 Then Result = tl Exit EndIf If tl = 0 Then Result = bl Exit EndIf
Dim matrix[bl, tl] For i = 0 To bl matrix[i, 0] = i Next For j = 0 To tl matrix[0, j] = j Next
For i = 1 To bl For j = 1 To tl If Copy(baseText, i, 1) = Copy(tryText, j, 1) Then cost = 0 Else cost = 1 EndIf Dim work[] = matrix[i-1, j] + 1, matrix[i, j-1] + 1, matrix[i-1, j-1] + cost matrix[i, j] = CalcArray(work, CALC_MIN) Next Next Result = matrix[bl, tl] FEnd
フォーム内のエレメントのNameやIdをCSVファイルに出力
IEでフォームを操作する時に使う。*3
Const CsvPath = GET_CUR_DIR + "\TagElementList.csv"
fid = FOpen(CsvPath, F_WRITE) If fid = -1 Then MsgBox(CsvPath + " をオープンできませんでした") ExitExit EndIf
url = Input("URLを入力してください<#CR>(空白時、現在IEでアクティブなURL)") If url = EMPTY Then ExitExit Try If Length(url) < 1 Then objIE = GetActiveOLEObj("InternetExplorer.Application") Else objIE = CreateOLEObj("InternetExplorer.Application") objIE.Visible = TRUE objIE.Navigate(url) Repeat Sleep(0.5) Until !objIE.Busy And (objIE.ReadyState = 4) EndIf Except MsgBox(TRY_ERRLINE + " 実行時エラー: " + TRY_ERRMSG + "が発生しました。中断します") ExitExit EndTry
FPut(fid, "Name", 1, 1) FPut(fid, "Id", 1, 2) FPut(fid, "Type", 1, 3) FPut(fid, "Name", 1, 4) FPut(fid, "Id", 1, 5) FPut(fid, "Value", 1, 6) y = 2 With objIE.Document For i = 0 To .Forms.Length - 1 FPut(fid, .Forms[i].Name, y, 1) FPut(fid, .Forms[i].Id, y, 2) y = y + 1 For j = 0 To .Forms[i].Elements.Length - 1 FPut(fid, .Forms[i].Elements[j].Type, y, 3) FPut(fid, .Forms[i].Elements[j].Name, y, 4) FPut(fid, .Forms[i].Elements[j].Id, y, 5) FPut(fid, .Forms[i].Elements[j].Value, y, 6) y = y + 1 Next Next EndWith FClose(fid) MsgBox("終了しました")
Excelワークシートに対してSQLで問い合わせ
1行目は見出し(列名)であること。
// Excelワークシートに対してSQLで問い合わせ(ADO) // 結果はクリップボードにコピーする
// 要2007 Office system ドライバ: データ接続コンポーネント // インストールされていない場合は https://www.microsoft.com/ja-jp/download/details.aspx?id=23734 からDL
//Const adOpenForwardOnly = 0 //Const adOpenKeyset = 1 //Const adLockReadOnly = 1 Const adUseClient = 3
Const DefaultFile = "" Const DefaultQuery = "SELECT COUNT(*) FROM [Sheet1$];"
Dim files = Input("Excelファイル(.xlsx;.xls)をドロップしてください。複数ドロップ時は最後のファイルを使用します", DefaultFile) If files = EMPTY Then ExitExit Dim arr = Split(files, "<#TAB>") Dim excelFile = arr[Resize(arr)] If FOpen(excelFile, F_EXISTS) <> TRUE Then MsgBox("ファイル " + excelFile + " は存在しません。中断します") ExitExit ElseIf Copy(excelFile, Length(excelFile) - 4) <> ".xlsx" And Copy(excelFile, Length(excelFile) - 3) <> ".xls" Then MsgBox("ファイル " + excelFile + " はExcelファイルではありません。中断します") ExitExit EndIf
Dim query = Input("SQLを入力してください", DefaultQuery) If query = EMPTY Then ExitExit
Dim objConnection = CreateOleObj("ADODB.Connection") Try objConnection.Open("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=<#DBL>" + excelFile + "<#DBL>;Extended Properties=<#DBL>Excel 12.0;HDR=YES;IMEX=1;<#DBL>;") Except MsgBox("Connectionオブジェクトの取得に失敗しました: " + TRY_ERRMSG + "<#CR>中断します") ExitExit EndTry objConnection.CursorLocation = adUseClient
Dim objRecordset = CreateOleObj("ADODB.Recordset") Try //objRecordset.Open(query, objConnection, adOpenForwardOnly, adLockReadOnly) objRecordset.Open(query, objConnection) Except MsgBox("クエリに失敗しました。恐らくSQL文が間違っています: " + TRY_ERRMSG + "<#CR>中断します") ExitExit EndTry
Dim report = "" If !objRecordset.EOF And objRecordset.Fields.Count > 0 Then // 見出しを作成 report = report + objRecordset.Fields(0).Name For i = 1 To objRecordset.Fields.Count - 1 report = report + "<#TAB>" + objRecordset.Fields(i).Name Next report = report + "<#CR>"
// 結果を作成 While !objRecordset.EOF report = report + objRecordset.Fields(0).Value For i = 1 To objRecordset.Fields.Count - 1 report = report + "<#TAB>" + objRecordset.Fields(i).Value Next report = report + "<#CR>" objRecordset.MoveNext WEnd
SendStr(0, report) EndIf
objRecordset.Close() objConnection.Close()
MsgBox("正常終了しました。結果はクリップボードにコピーされます")
Outlookで新規メールアイテムを作成
Const olMailItem = 0
// 送信先メールアドレス:複数指定時は ; で区切る toAddress = "送り先メールアドレス" ccAddress = "" bccAddress = ""
// サブジェクト subject = "TEST"
// %APPDATA%\Microsoft\Signatures\ フォルダ下にある署名ファイル(.txt) signFile = "署名.txt"
TextBlock message :(ここにメール文面) EndTextBlock
objOutlook = GetActiveOleObj("Outlook.Application") objMailItem = objOutlook.CreateItem(olMailItem) With objMailItem If Length(toAddress) > 0 Then .To = toAddress If Length(ccAddress) > 0 Then .Cc = ccAddress If Length(bccAddress) > 0 Then .Bcc = bccAddress .Subject = subject .Body = message If Length(signFile) > 0 Then .Body = .Body + "<#CR>" + GetSignatures(signFile) EndWith objMailItem.Display(FALSE)
Function GetSignatures(file) fid = FOpen(GET_APPDATA_DIR + "\Microsoft\Signatures\" + file, F_READ) Result = FGet(fid, F_ALLTEXT) FClose(fid) FEnd
Outlookのメール着信を監視
Try objOutlook = GetActiveOleObj("Outlook.Application") Except MsgBox("Outlook が起動していません: " + TRY_ERRMSG + "<#CR>終了します", BTN_OK) ExitExit EndTry OleEvent(objOutlook, "ApplicationEvents_11", "NewMailEx", "OL_NewMailEx") OleEvent(objOutlook, "ApplicationEvents_11", "Quit", "OL_Quit") While TRUE Sleep(500) WEnd
Procedure OL_NewMailEx(id) MsgBox("OL_NewMailEx() Called.") FEnd
Procedure OL_Quit() ExitExit FEnd
nMail.dll利用
// nMail.dllを使ったメール送信(nMail.dllはhttp://www.nanshiki.co.jp/からDL)
DEF_DLL NMailInitializeWinSock(): int: nMail DEF_DLL NMailGetVersion(): int: nMail DEF_DLL NMailSmtpSendMailPortNoW(Wstring, Wstring, Wstring, Wstring, Wstring, Wstring, Wstring, Wstring, Wstring, int, int): uint: nMail DEF_DLL NMailEndWinSock(): int: nMail
NMailInitializeWinSock() //MsgBox("NMailGetVersion = " + NMailGetVersion())
smtp = "SMTPサーバ名" toAdr = "送信先メールアドレス" ccAdr = NULL bccAdr = NULL fromAdr = "送信元メールアドレス" subject = "サブジェクト" body = "本文" header = NULL path = NULL flag = 0 port = 25 MsgBox("NMailSmtpSendMailPortNoW = " + NMailSmtpSendMailPortNoW(smtp, toAdr, ccAdr, bccAdr, fromAdr, subject, body, header, path, flag, port))
NMailEndWinSock()
動作記録用Meryマクロ
「動作記録」で作成したUWSCファイルを加工するMery用マクロ(JScript)。
マウスの動きを遅らせる
「余分な時間、マウス移動は記録しない」をチェックした場合に使う。
#title = "SLEEP()を挿入する" #tooltip = "マウスの動きを遅らせる" // UWSCマクロにおいて一行ごとにSLEEP()を挿入する(操作を遅くする;キーボード操作中は対象外) // 使い方: // 1. 「動作記録」で作成したUWSCマクロをMeryで開く // 2. マウスの動きを遅くしたい箇所を範囲選択する // 3. 当マクロを実行 var w = "SLEEP(2)"; // 2秒ウェイトを入れる var s1 = document.selection.Text.split("\n"); var s2 = new Array(); for (var i = 0; i < s1.length; i++) { s2.push(s1[i]); if (i < s1.length - 1) { if (s1[i].length > 0 && s1[i].substr(0, 4) != "KBD(") s2.push(w); else if (s1[i].substr(0, 4) == "KBD(" && s1[i+1].length > 0 && s1[i+1].substr(0, 4) != "KBD(") s2.push(w); } } document.selection.Text = s2.join("\n");
マウスの動きを速める
「余分な時間、マウス移動は記録しない」をチェックしていない場合に使う。
その1
#title = "MMV()の第三引数の値を一割小さくする(直接書換え)" #tooltip = "マウスの動きを速める" // UWSCマクロにおいてMMV()の第三引数の値を一割小さくする(マウスの動きを速める) // 使い方: // 1. 「動作記録」で作成したUWSCマクロをMeryで開く // 2. マウスの動きを速めたい箇所を範囲選択する // 3. 当マクロを実行 var p = 0.9; var r1 = /^MMV\(\d+,\d+,(\d+)\)$/; var r2 = /^(MMV\(\d+,\d+,)\d+(\))$/; var s1 = document.selection.Text.split("\n"); var s2 = new Array(); for (var i = 0; i < s1.length; i++) { if (s1[i].substr(0, 4) == "MMV(") { x = parseFloat(s1[i].replace(r1, "$1")); if (isNaN(x)) { s2.push(s1[i]); } else { x2 = Math.ceil(x * p); s2.push(s1[i].replace(r2, "$1" + x2.toString() + "$2")); } } else s2.push(s1[i]); } document.selection.Text = s2.join("\n");
その2
#title = "MMV()の第三引数の値を一割小さくする(*0.9版)" #tooltip = "マウスの動きを速める" // UWSCマクロにおいてMMV()の第三引数の値を一割小さくする(マウスの動きを速める) // 使い方: // 1. 「動作記録」で作成したUWSCマクロをMeryで開く // 2. マウスの動きを速めたい箇所を範囲選択する // 3. 当マクロを実行 var p = 0.9; // この値で速度調整 var r = /^(MMV\(\d+,\d+,\d+)(\))$/; var s1 = document.selection.Text.split("\n"); var s2 = new Array(); for (var i = 0; i < s1.length; i++) { if (r.test(s1[i])) s2.push(s1[i].replace(r, "$1*" + p.toString() + "$2")); else s2.push(s1[i]); } document.selection.Text = s2.join("\n");
ランチメニュ向け
クリップボード中のフォルダのパスでエクスプローラを開く
DosCmd("explorer.exe " + Trim(GetStr(0)))
クリップボード中のURLでIEを開く
objIE = CreateOLEObj("InternetExplorer.Application") objIE.Visible = TRUE objIE.Navigate(Trim(GetStr(0)))
クリップボード中のURLでEdgeを開く
DosCmd("start microsoft-edge:" + Trim(GetStr(0)))
その他
- 関数、手続きはメインロジックの下に記述せねばならない(凄い嵌った)