印刷ジョブがキャンセルできなくなった時にジョブを空にする

PC上で印刷実行したのに何時までもプリンターでの印刷が始まらず、印刷ジョブをキャンセルしてもキャンセルされないまま止まった状態が続く事がある。
プリンターの調子が悪いのかと思い、プリンターを再起動してみるも変わらず、USBやLAN等の接続に問題があると思い、接続し直す等の処理をしても結果は変わらず、PCを再起動してようやく治る事が多い。
しかし、多くのウインドウやアプリを開いたままの作業中に、一旦作業を中断して再起動を行うのは時間と手間が掛かるので、なるべく再起動をせずに不具合を治したい。
そんな時、以下の方法で治す事ができる。

dynabook.com | サポート情報 | 印刷ジョブを削除しても、ジョブが消えない<Windows(R)7>
http://www.dynabook.com/assistpc/faq/pcdata/010958.htm

作業内容を要約すると以下の手順となる。

  1. サービス"Print Spooler"を停止
  2. Print Spoolerのキャッシュフォルダ("C:\Windows\System32\spool\PRINTERS")内のファイルを全て削除
  3. サービス"Print Spooler"を再起動

しかし、この手順を印刷ジョブが消えなくなる度に行うのは色々と面倒なので、バッチ処理でできないか考える。
サービスの起動・終了をバッチ処理で行うには、以下の方法を使う。

バッチ で Windowsサービス を 起動、終了 する 方法 - galife
https://garafu.blogspot.com/2014/05/windows.html

これらを参考に、印刷ジョブを消すバッチ処理を書いてみる。
※注意:コマンドプロンプトからのファイル削除(復元不可)を行うため、自己責任で実行してください。

echo off

rem サービス名を設定
set SERVICENAME=Print Spooler

rem 空にするフォルダパスを設定
set FOLDERPATH=C:\Windows\System32\spool\PRINTERS

rem サービス中断
echo stopping %SERVICENAME%
net stop "%SERVICENAME%"

rem フォルダを空にする
echo emptying %FOLDERPATH%\*.*
del "%FOLDERPATH%\*.*"

rem サービス起動
echo starting %SERVICENAME%
net start "%SERVICENAME%"

pause

echo on

作業結果は以下の通り。(管理者として実行)

VB6ランタイムをWin8.1にインストールする際のトラブルシューティング覚え書き

VB6ランタイムが必要なアプリを起動しようとしたら、ランタイムが不足していて起動できなかったので、ランタイムをVectorからダウンロードしてインストールしてみた所、問題が起きた。

トラブル内容:
VB6SP6ランタイムのインストール時に、「エラー 2709 オフライン参加完了情報が見つかりませんでした。」のエラーが出てインストール出来ない。
動作環境:Windows 8.1 64bit

互換性の問題かと思い、トラブルシューティングで最適設定を探してWindows XP SP3互換の管理者権限でテストしてみたが改善なし。(互換性は無関係?)
仕方ないのでエラーメッセージで検索してみた所、いくつかの情報源に当たり、レジストリを弄ってようやくインストール成功。

手順を自分なりに分かりやすくまとめてみた。

regedit(レジストリエディタ)で以下の編集を行う。

  1. HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windowsの下にInstallerという名前のキーが無い場合、新規に作る(あればそのまま)。
  2. InstallerキーにSecureRepairPolicyという名前のDWORD値(32ビット)を作成し、値データ(16進数)を2にする。
  3. Installerの下にSecureRepairWhitelistという名前のキーを作る。
  4. SecureRepairWhitelistキーに製品コードを名前に持つ文字列値を追加する(内容は空)。
    VB6SP6ランタイムの場合、製品コードは「{59FEFE3F-8119-457C-A4EE-CF24202DD9D2}」なので、それをそのまま文字列の名前にする。

参考URL:
VB6SP6ランタイムのインストールエラーについて質問です。VB6SP6ランタ... - Yahoo!知恵袋:
http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q10137549285
[MS14-049] Windows Installer サービス用のセキュリティ更新プログラムについて(2014年8月12日)
http://support.microsoft.com/kb/2918614/ja

なでしこでHEXマップの2点間距離計算をする

HEXマップとは

六角形のチップが隙間無く配置されたマップ形式。
マップ上の距離感覚が直観的で分かりやすいため、シミュレーションゲーム等で使われる。
短所は、データをX,Y座標系で扱う場合の管理が難しい事と距離計算が複雑になる事。

距離計算式を作る

今回は、1000×1000のチップが配置されたHEXマップの距離計算を行う。
なお、チップの配置と座標の関係は次のようにする。

[0,0][1,0][2,0][3,0]
[0,1][1,1][2,1][3,1]
[0,2][1,2][2,2][3,2]
[0,3][1,3][2,3][3,3]

Y座標が偶数のマスと奇数のマスで半マス分ずらして表示する形となる。

この場合、それぞれ[x,y]に隣接するマスは次のようになる。

(y:偶数の場合)
[x-1,y-1][x,y-1]
[x-1,y][x,y][x+1,y]
[x-1,y+1][x,y+1]
(y:奇数の場合)
[x,y-1][x+1,y-1]
[x-1,y][x,y][x+1,y]
[x,y+1][x+1,y+1]

[x,y]のマスを中心に見た場合、Y方向に線対称、X方向に非対称となる事が分かる。
隣接するマス同士の距離を1とすると、2点間の距離は隣接するマスへの移動の繰り返しとなるので、例えば[2,0]から移動する場合、[0,3]から[3,3]までの同じY座標の範囲のどこに移動しても距離は同じ3となる。(この範囲からX方向に外れると、外れた分だけ距離が加算される。)

[0,0][1,0][2,0][3,0]
[0,1][1,1][2,1][3,1]
[0,2][1,2][2,2][3,2]
[0,3][1,3][2,3][3,3]

これらを合わせて考えると、距離の計算式は以下のようになる。
 \left[ x_{a}, y_{a} \right] から \left[ x_{b}, y_{b} \right] までの距離

  • y_a, y_b:ともに偶数, または奇数の場合

 dist =
 \left\{ \begin{matrix} \left| x_b - x_a \right| \leq \frac{\left| y_b - y_a \right| }{2} & \rightarrow & \left| y_b - y_a \right| \\ \left| x_b - x_a \right| \gt \frac{\left| y_b - y_a \right| }{2} & \rightarrow & \left| y_b - y_a \right| + \left( \left| x_b - x_a \right| - \frac{ \left| y_b - y_a \right| }{2} \right) \end{matrix} \right\}
(偶数同士・奇数同士の移動では同じX座標で半マス分ずれる事を考える必要が無いため、数式は単純となる)

  • y_a:偶数, y_b:奇数の場合
    •  x_a < x_a の場合

 dist =
 \left\{ \begin{matrix} \left| x_b - x_a \right| \leq \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil & \rightarrow & \left| y_b - y_a \right| \\ \left| x_b - x_a \right| \gt \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil & \rightarrow & \left| y_b - y_a \right| + \left( \left| x_b - x_a \right| - \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil \right) \end{matrix} \right\}

    •  x_a \geq x_a の場合

 dist =
 \left\{ \begin{matrix} \left| x_b + 1 - x_a \right| \leq \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil & \rightarrow & \left| y_b - y_a \right| \\ \left| x_b + 1 - x_a \right| \gt \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil & \rightarrow & \left| y_b - y_a \right| + \left( \left| x_b + 1 - x_a \right| - \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil \right) \end{matrix} \right\}

  • y_a:奇数, y_b:偶数の場合
    •  x_a \lt x_a の場合

 dist =
 \left\{ \begin{matrix} \left| x_b - 1 - x_a \right| \leq \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil & \rightarrow & \left| y_b - y_a \right| \\ \left| x_b - 1 - x_a \right| \gt \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil & \rightarrow & \left| y_b - y_a \right| + \left( \left| x_b - 1 - x_a \right| - \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil \right) \end{matrix} \right\}

    •  x_a \geq x_a の場合

 dist =
 \left\{ \begin{matrix} \left| x_b - x_a \right| \leq \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil & \rightarrow & \left| y_b - y_a \right| \\ \left| x_b - x_a \right| \gt \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil & \rightarrow & \left| y_b - y_a \right| + \left( \left| x_b - x_a \right| - \lceil \frac{ \left| y_b - y_a \right| }{2} \rceil \right) \end{matrix} \right\}

プログラムの条件分岐として記述する場合、これだけ複雑になると分かりづらくなるため、もっと単純化してみる。
Y方向の距離:
 {\Delta}_y = \left| y_b - y_a \right|
移動先Y座標における等距離マス群の幅の半分(遊び幅):
 {\beta}_{x} = \lceil \frac{ {\Delta}_{y} }{2} \rceil
X方向の距離:
 {\Delta}_x = \left\{ \begin{matrix} {\Delta}_y mod 2 = 0 & & & & & \rightarrow & \left| x_b - x_a \right| \\ {\Delta}_y mod 2 \not= 0 & , & y_a mod 2 = 0 & , & x_b \lt x_a & \rightarrow & \left| x_b - x_a \right| \\ {\Delta}_y mod 2 \not= 0 & , & y_a mod 2 = 0 & , & x_b \geq x_a & \rightarrow & \left| x_b + 1 - x_a \right| \\ {\Delta}_y mod 2 \not= 0 & , & y_a mod 2 \not= 0 & , & x_b \lt x_a & \rightarrow & \left| x_b - 1 - x_a \right| \\ {\Delta}_y mod 2 \not= 0 & , & y_a mod 2 \not= 0 & , & x_b \geq x_a & \rightarrow & \left| x_b - x_a \right| \end{matrix} \right\}
距離:
 dist = \left\{ \begin{matrix} {\Delta}_x \leq {\beta}_x & \rightarrow & {\Delta}_y \\ {\Delta}_x \gt {\beta}_x & \rightarrow & {\Delta}_y + \left( {\Delta}_x - {\beta}_x \right) \end{matrix} \right\}

さらに、HEXマップの端と端が隣接するトーラス状の非ユークリッド平面と考えた場合、X方向とY方向の距離計算をそれぞれ変える必要が出てくる。

[998,996][999,996][0,996][1,996]
[998,997][999,997][0,997][1,997]
[998,998][999,998][0,998][1,998]
[998,999][999,999][0,999][1,999]
[998,0][999,0][0,0][1,0]
[998,1][999,1][0,1][1,1]
[998,2][999,2][0,2][1,2]
[998,3][999,3][0,3][1,3]

その場合、以下の計算式を加える。
画面サイズ(X,Yともに2の倍数にする):
 W_x = 1000, W_y = 1000
Y方向のトーラス距離:
 {\Delta }_{yT} = \frac{W_y}{2} - \left| \left( {\Delta}_y mod W_y \right) - \frac{W_y}{2} \right|
X方向のトーラス距離:
 {\Delta }_{xT} = \frac{W_x}{2} - \left| \left( {\Delta}_x mod W_x \right) - \frac{W_x}{2} \right|
移動先Y座標における(トーラス平面上の)等距離マス群の幅の半分(遊び幅):
 {\beta}_{xT} = \lceil \frac{ {\Delta}_{yT} }{2} \rceil
トーラス距離:
 distT = \left\{ \begin{matrix} {\Delta}_{xT} \leq {\beta}_{xT} & \rightarrow & {\Delta}_{yT} \\ {\Delta}_{xT} \gt {\beta}_{xT} & \rightarrow & {\Delta}_{yT} + \left( {\Delta}_{xT} - {\beta}_{xT} \right) \end{matrix} \right\}

なでしこで実装

上記の計算式を元に、なでしこで距離計算プログラムを作成する。
動作の流れは、移動元と移動先の座標(X,Y)を入力後、計算結果が表示されるというものである。
なお、できるだけ簡素にするため範囲内の整数か否かの入力チェックは行わない。

画面サイズXとは数値
画面サイズYとは数値
移動元Xとは数値
移動元Yとは数値
移動先Xとは数値
移動先Yとは数値
ユークリッド距離Xとは数値
ユークリッド距離Yとは数値
トーラス距離Xとは数値
トーラス距離Yとは数値
遊び幅Xとは数値
ヘキサ距離とは数値
計算結果とは文字列

画面サイズXは1000
画面サイズYは1000

▲開始地点

「移動元のX座標を入力してください。」で尋ねる
移動元Xはそれ
「移動元のY座標を入力してください。」で尋ねる
移動元Yはそれ
「移動先のX座標を入力してください。」で尋ねる
移動先Xはそれ
「移動先のY座標を入力してください。」で尋ねる
移動先Yはそれ

ユークリッド距離Yは(移動先Y−移動元Y)の絶対値
トーラス距離Yは(画面サイズY÷2−((ユークリッド距離Yを画面サイズYで割った余り−画面サイズY÷2)の絶対値))

もしトーラス距離Yを2で割った余りが0ならば
	ユークリッド距離Xは(移動先X−移動元X)の絶対値
	遊び幅Xはトーラス距離Y÷2
違えば
	もし移動元Yを2で割った余りが0ならば
		もし移動先Xが移動元X未満ならば ユークリッド距離Xは(移動先X−移動元X)の絶対値
		違えば ユークリッド距離Xは(移動先X+1−移動元X)の絶対値
	違えば
		もし移動先Xが移動元X未満ならば ユークリッド距離Xは(移動先X−1−移動元X)の絶対値
		違えば ユークリッド距離Xは(移動先X−移動元X)の絶対値
	遊び幅Xは(トーラス距離Y÷2)を切り上げ

トーラス距離Xは(画面サイズX÷2−((ユークリッド距離Xを画面サイズXで割った余り−画面サイズX÷2)の絶対値))

もしトーラス距離Xが遊び幅X以下ならば ヘキサ距離はトーラス距離Y
違えば ヘキサ距離はトーラス距離Y+(トーラス距離X−遊び幅X)

計算結果は「」
計算結果に「移動元(」を追加
計算結果に移動元Xを追加
計算結果に「,」を追加
計算結果に移動元Yを追加
計算結果に「)→移動先(」を追加
計算結果に移動先Xを追加
計算結果に「,」を追加
計算結果に移動先Yを追加
計算結果に「)の距離=」を追加
計算結果にヘキサ距離を追加
計算結果を表示

「続けますか?」で二択
もし それがいいえならば 終了

「開始地点」に飛ぶ

実行結果



なでしこ(日本語プログラミング言語)を使ってみる

なでしこ:日本語プログラミング言語
http://nadesi.com/top/

最新版(1.544)をダウンロードしてインストールして使ってみた。
ZIPとEXEがあるので、どちらかを選んでダウンロードする。
自分は初めてなのでEXEで自動インストールした。

起動すると、デモとチュートリアルを見ることができるので、それらを一通り見た後、一番簡単なコマンドを打って走らせてみた。

Hello! Worldの日本語版を表示するプログラムを書いて実行する。

「言う(いう)」だけだとダイアログが表示される。

「おわり」でプログラム終了を宣言しておくと、自動で母艦ウインドウが閉じて、プログラムが終了する。

他にもグリッド表示や定型処理、ファイル処理、画像処理など色々できるらしいので、いじってみようと思う。

指定フォルダ内の重複ファイルを検出するプログラムの修正

指定フォルダ内の重複ファイルを検出するプログラムを参照の事。
サイズ0のファイルが検出されたり、3つ以上の重複ファイルが2つ以上の組み合わせに分かれていたりと、大量のファイルを扱うには不便な箇所が色々と見つかったので、修正。
空のファイルを無視し、3つ以上の重複ファイルを一纏めにして表示するように変更した。

use utf8;
use strict;
use warnings;
use File::Find::Iterator;
use File::Compare;

# File::Find::Iterator
my $find;
# filter用サブルーチン
sub isdir { -d }
sub isfile { -f -s }

# ファイル比較後、重複ファイルの組合わせをハッシュで返す。
sub binary_compare {
	my @file_list = @_;
	my $same_list = {};
	my @dub_files = ();
	
	for (my $i = 0; $i + 1 < @file_list; $i++) {
		next if (grep ($file_list[$i], @dub_files) > 0);
		for (my $j = $i + 1; $j < @file_list; $j++) {
			my $diff = 0;
			$diff = compare($file_list[$i], $file_list[$j]);
			if ($diff == 0) {
				if (exists $same_list->{$file_list[$i]}) {
					push @{$same_list->{$file_list[$i]}}, $file_list[$j];
				} else {
					$same_list->{$file_list[$i]} = [$file_list[$j]];
				}
				push @dub_files, $file_list[$j];
			}
		}
	}
	
	return $same_list;
}

# ベースディレクトリ(指定なしの場合カレントディレクトリ)
my $base_dir = $ARGV[0] || './';
# 区切り文字'\'を'/'に変換する
$base_dir =~ s/\\/\//gso;

# ファイル一覧取得
my @file_list;
$find = File::Find::Iterator->create(dir => [$base_dir], filter => \&isfile);
while (my $f = $find->next) { push (@file_list, $f) }

my %file_size_hash_table = ();
foreach my $file_name (@file_list) {
	my $file_size = -s $file_name;
	$file_size_hash_table{$file_size} = [] unless exists $file_size_hash_table{$file_size};
	push @{$file_size_hash_table{$file_size}}, $file_name;
}

foreach my $file_size (sort keys %file_size_hash_table) {
	my $files = $file_size_hash_table{$file_size};
	
	next unless (@{$files} > 1);
	
	my $same_list = binary_compare(sort @{$files});
	
	foreach my $same_files_head (sort keys %{$same_list}) {
		my $same_files = $same_list->{$same_files_head};
		print $same_files_head;
		foreach my $same_file (@$same_files) {
			print ' == ' . $same_file;
		}
		print '(' . $file_size . ' B)' . "\n";
	}
}

サクラエディタ外部マクロのJavaScript

Perlスクリプトは環境によってはWSHがサポートしていない場合もあるので、色んなマシンで使い回す事を考えるなら、JavaScriptで記述するのが無難だと思う。
よって、JavaScriptでHTMLタグ挿入マクロを書いてみる。

// tag_sub.js
var name = 'sub';
if (IsTextSelected() == 0) {
	InsText('<' + name + '></' + name + '>');
} else if (IsTextSelected() == 1) {
	InsText('<' + name + '>' + GetSelectedString(0) + '</' + name + '>');
}
ReDraw(0);

これも、変数nameの内容を変えれば、色んなタグに応用できる。

サクラエディタ外部マクロのPerlスクリプト

サクラエディタではユーザーが作成したマクロを登録でき、キーマクロ(mac)や、その他WSH(Windows Scripting Host)で使用可能なスクリプト言語(js, vbs等)を使って記述することもできる。
WSHがサポートしていればPerlスクリプト(pls)も使えるので、それで複雑な文字列操作マクロを作成し、コマンドとして実行することもできる。
以下は選択文字列の前後にHTMLタグを挿入するマクロ。

# tag_sub.pls
$name = 'sub';
if (IsTextSelected() == 0) {
	InsText("<$name></$name>");
} elsif (IsTextSelected() == 1) {
	InsText("<$name>" . GetSelectedString(0) . "</$name>");
}
ReDraw(0);

変数$nameの内容を変えれば、色んなタグに応用できる。
キーマクロでも記述できるが、以下のような手順となる。

  • 選択文字列をカットする。(クリップボードの内容が選択文字列に書き換わる。カーソルは選択文字列のあった位置になる。)
  • カーソル位置に始点タグを挿入する。(カーソルが始点タグの直後に移動する。)
  • クリップボードから選択文字列をペーストする。(カーソルが選択文字列の直後に移動する。)
  • カーソル位置に終点タグを挿入する。(カーソルが終点タグの直後に移動する。)

選択文字列をカット&ペーストする操作が必要であり、クリップボードを書き換えてしまう。さらに、1操作で終わらないため、後戻りする際、何回もアンドゥする手間が掛かる。また、後戻りする途中で元の選択文字列が一旦消えるため、中断したまま他の作業をすると、元の選択文字列が戻ってこない危険性がある。
その点、上記のPerlスクリプトで選択文字列部分を一度に置き換えてしまえば、変数が使えるのでクリップボードを使わずに済み、1操作で終わるため、1回のアンドゥで済む。何より、タグ挿入を一連の不可分な操作として考えた場合、実際の動作上でも1回の操作として扱うため、直観的で分かりやすい。