「上書き保存(UAC対応)」の版間の差分

提供: MeryWiki
ナビゲーションに移動 検索に移動
MSY-07 (トーク | 投稿記録)
スペースからタブに変更
MSY-07 (トーク | 投稿記録)
SyntaxHighlightにcopyの追加
 
(同じ利用者による、間の4版が非表示)
36行目: 36行目:
* 「外部でファイルが変更されています」のメッセージが表示される
* 「外部でファイルが変更されています」のメッセージが表示される
* UAC 制御画面でキャンセルしても編集マーク(*)が消える(実際には保存されていない)
* UAC 制御画面でキャンセルしても編集マーク(*)が消える(実際には保存されていない)
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript" copy>
#title="上書き保存"
#title="上書き保存"


51行目: 51行目:


// 『無題』は通常処理
// 『無題』は通常処理
if (!Document.Name) {
if (!document.Name) {
Document.Save();
document.Save();
Quit();
Quit();
}
}


// 変更がない場合は保存しない
// 変更がない場合は保存しない
if (Document.Saved) {
if (document.Saved) {
Quit();
Quit();
}
}
63行目: 63行目:
// ファイルがない場合は通常処理(Mery準拠)
// ファイルがない場合は通常処理(Mery準拠)
var fso = new ActiveXObject("Scripting.FileSystemObject");
var fso = new ActiveXObject("Scripting.FileSystemObject");
if (!fso.FileExists(Document.FullName)) {
if (!fso.FileExists(document.FullName)) {
Document.Save();
document.Save();
Quit();
Quit();
}
}


// 書き込み禁止か取得
// 書き込み禁止か取得
var file = fso.GetFile(Document.FullName);
var file = fso.GetFile(document.FullName);
if (file.Attributes & 0x01) {
if (file.Attributes & 0x01) {
Alert("このファイルは読み取り専用です");
Alert("このファイルは読み取り専用です");
76行目: 76行目:


// UAC の判定
// UAC の判定
if (!IsNeedUAC(Document.FullName)) {
if (!IsNeedUAC(document.FullName)) {
Document.Save();
document.Save();
Quit();
Quit();
}
}
84行目: 84行目:
var shell = new ActiveXObject("Wscript.Shell");
var shell = new ActiveXObject("Wscript.Shell");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var tempFilePath = fso.BuildPath(folder, Document.Name);
var tempFilePath = fso.BuildPath(folder, document.Name);
SaveToFile(tempFilePath, Document);
SaveToFile(tempFilePath, Document);


var appShell = new ActiveXObject("Shell.Application");
var appShell = new ActiveXObject("Shell.Application");
appShell.ShellExecute("cmd.exe", '/c COPY /Y "' + tempFilePath +'" "' + Document.FullName + '" & DEL "' + tempFilePath + '"', "", "runas", 2);
appShell.ShellExecute("cmd.exe", '/c COPY /Y "' + tempFilePath +'" "' + document.FullName + '" & DEL "' + tempFilePath + '"', "", "runas", 2);
UpdateSavedMark(true);
UpdateSavedMark(true);


133行目: 133行目:
var charset = "utf-8";
var charset = "utf-8";
switch (doc.Encoding) {
switch (doc.Encoding) {
case meEncodingEUC:                   charset = "euc-JP";   break;
case meEncodingUTF16LEBOM:
case meEncodingShiftJIS:             charset = "shift-jis"; break;
case meEncodingUTF16LENoBOM:
case meEncodingUTF16LE:
case meEncodingUTF16BEBOM:
case meEncodingUTF16BE:               charset = "unicode"; break;
case meEncodingUTF16BENoBOM: charset = "unicode";     break;
case meEncodingUTF7:                 charset = "utf-7";   break;
case meEncodingUTF8BOM:
case meEncodingUTF8WithSignature:
case meEncodingUTF8NoBOM:     charset = "utf-8";       break;
case meEncodingUTF8WithoutSignature:  charset = "utf-8";    break;
case meEncodingUTF7:         charset = "utf-7";        break;
case meEncodingEUC:           charset = "euc-JP";       break;
case meEncodingJIS:           charset = "iso-2022-jp"; break;
case meEncodingShiftJIS:     charset = "shift-jis";    break;
}
}


149行目: 152行目:


// BOM 削除処理
// BOM 削除処理
if (doc.Encoding == meEncodingUTF8WithoutSignature) {
if (doc.Encoding == meEncodingUTF8NoBOM) {
adodb.Position = 0;
adodb.Position = 0;
adodb.Type = 1;
adodb.Type = 1;
167行目: 170行目:
// すぐに反映されないので対処
// すぐに反映されないので対処
function UpdateSavedMark(isSaved) {
function UpdateSavedMark(isSaved) {
if (Document.Saved != isSaved) {
if (document.Saved != isSaved) {
Document.Saved = isSaved;
document.Saved = isSaved;
var sel = Document.Selection;
var sel = document.selection;
if (sel.GetActivePointX(mePosLogical) == 1 && sel.GetActivePointY(mePosLogical) == 1) {
if (sel.GetActivePointX(mePosLogical) == 1 && sel.GetActivePointY(mePosLogical) == 1) {
sel.CharLeft();
sel.CharLeft();
183行目: 186行目:
副作用(制限)
副作用(制限)
* 元に戻す、やり直しの履歴が削除される
* 元に戻す、やり直しの履歴が削除される
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript" copy>
#title="上書き保存"
#title="上書き保存"


196行目: 199行目:


// 『無題』は通常処理
// 『無題』は通常処理
if (!Document.Name) {
if (!document.Name) {
Document.Save();
document.Save();
Quit();
Quit();
}
}


// 変更がない場合は保存しない
// 変更がない場合は保存しない
if (Document.Saved) {
if (document.Saved) {
Quit();
Quit();
}
}
208行目: 211行目:
// ファイルがない場合は通常処理(Mery準拠)
// ファイルがない場合は通常処理(Mery準拠)
var fso = new ActiveXObject("Scripting.FileSystemObject");
var fso = new ActiveXObject("Scripting.FileSystemObject");
if (!fso.FileExists(Document.FullName)) {
if (!fso.FileExists(document.FullName)) {
Document.Save();
document.Save();
Quit();
Quit();
}
}


// 書き込み禁止か取得
// 書き込み禁止か取得
var file = fso.GetFile(Document.FullName);
var file = fso.GetFile(document.FullName);
if (file.Attributes & 0x01) {
if (file.Attributes & 0x01) {
Alert("このファイルは読み取り専用です");
Alert("このファイルは読み取り専用です");
221行目: 224行目:


// UAC の判定
// UAC の判定
if (!IsNeedUAC(Document.FullName)) {
if (!IsNeedUAC(document.FullName)) {
Document.Save();
document.Save();
Quit();
Quit();
}
}
228行目: 231行目:
var shell = new ActiveXObject("Wscript.Shell");
var shell = new ActiveXObject("Wscript.Shell");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var tempFilePath = fso.BuildPath(folder, Document.Name);
var tempFilePath = fso.BuildPath(folder, document.Name);


// 保存前の状態を保持
// 保存前の状態を保持
var sel = Document.Selection;
var sel = document.selection;
var latestText = Document.Text;
var latestText = document.Text;
var sx = ScrollX, sy = ScrollY;
var sx = ScrollX, sy = ScrollY;
var tx = sel.GetTopPointX(mePosLogical), ty = sel.GetTopPointY(mePosLogical);
var tx = sel.GetTopPointX(mePosLogical), ty = sel.GetTopPointY(mePosLogical);
var bx = sel.GetBottomPointX(mePosLogical), by = sel.GetBottomPointY(mePosLogical);
var bx = sel.GetBottomPointX(mePosLogical), by = sel.GetBottomPointY(mePosLogical);
var filePath = Document.FullName;
var filePath = document.FullName;


// 一時ファイルに保存して UAC 対応ムーブ
// 一時ファイルに保存して UAC 対応ムーブ
Document.Saved = true;
document.Saved = true;
Document.Save(tempFilePath);
document.Save(tempFilePath);
var appShell = new ActiveXObject("Shell.Application");
var appShell = new ActiveXObject("Shell.Application");
appShell.ShellExecute("cmd.exe", '/c COPY /Y "' + tempFilePath +'" "' + filePath + '" & DEL "' + tempFilePath + '"', "", "runas", 2);
appShell.ShellExecute("cmd.exe", '/c COPY /Y "' + tempFilePath +'" "' + filePath + '" & DEL "' + tempFilePath + '"', "", "runas", 2);
254行目: 257行目:
// ファイルを開き直す
// ファイルを開き直す
// UACの昇格を拒否されていた場合は、エディタ上の内容だけ書き換え
// UACの昇格を拒否されていた場合は、エディタ上の内容だけ書き換え
Editor.OpenFile(filePath);
editor.OpenFile(filePath);
var doc = Editor.ActiveDocument
var doc = editor.ActiveDocument
if (doc.Text != latestText) {
if (doc.Text != latestText) {
doc.Text = latestText;
doc.Text = latestText;

2025年6月30日 (月) 00:18時点における最新版

概要[編集]

UAC に対応した「上書き保存」マクロです。

バグ[編集]

2013-02-01 以前までのコードにはセキュリティリスクのあるバグが含まれていました。

現象
ファイルのアクセス権限が書き換えられる。
結果として管理者権限がなくてもファイルを書き換えることが可能となる。
(実行時のユーザのアクセス権限がフルアクセスになる)
条件
TEMP がユーザフォルダ配下にある(デフォルト状態)

変更履歴[編集]

  • 1.0.1 (2013-02-02)
    • バグ修正&UAC判定の強化
  • 1.0.0 (2013-01-27)
    • 初版

注意事項[編集]

  • 若干の副作用(制限)があります。
  • 環境変数「TEMP」にアクセスします。
  • 「TEMP」フォルダ配下の同名ファイルを書き換えます。

使用方法[編集]

  1. コードを js ファイルにしてマクロを登録する。
  2. 必要があれば、Ctrl+S に登録する。

ソースコード[編集]

副作用(制限)が異なる2パターンのコードがあるので、 より制限を許容できる方のコードをご使用ください。

パターン1[編集]

副作用(制限)

  • 改行コードは固定
  • 「外部でファイルが変更されています」のメッセージが表示される
  • UAC 制御画面でキャンセルしても編集マーク(*)が消える(実際には保存されていない)
#title="上書き保存"

// -----------------------------------------------------------------------------
// Overwrite.js
//
// UAC対応の上書き保存
//
// (C) ks
// http://merysmacro.seesaa.net/
// -----------------------------------------------------------------------------

var NEWLINE_CODE = "\r\n"

// 『無題』は通常処理
if (!document.Name) {
	document.Save();
	Quit();
}

// 変更がない場合は保存しない
if (document.Saved) {
	Quit();
}

// ファイルがない場合は通常処理(Mery準拠)
var fso = new ActiveXObject("Scripting.FileSystemObject");
if (!fso.FileExists(document.FullName)) {
	document.Save();
	Quit();
}

// 書き込み禁止か取得
var file = fso.GetFile(document.FullName);
if (file.Attributes & 0x01) {
	Alert("このファイルは読み取り専用です");
	Quit();
}

// UAC の判定
if (!IsNeedUAC(document.FullName)) {
	document.Save();
	Quit();
}

// 一旦別のファイルに保存して、UAC対応コピー処理
var shell = new ActiveXObject("Wscript.Shell");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var tempFilePath = fso.BuildPath(folder, document.Name);
SaveToFile(tempFilePath, Document);

var appShell = new ActiveXObject("Shell.Application");
appShell.ShellExecute("cmd.exe", '/c COPY /Y "' + tempFilePath +'" "' + document.FullName + '" & DEL "' + tempFilePath + '"', "", "runas", 2);
UpdateSavedMark(true);


//==============================================================================
// 関数定義

// UAC が必要かを判定
function IsNeedUAC(path) {
	if (!path) {
		return false;
	}

	// 書き込み可能か確認
	var fso = new ActiveXObject("Scripting.FileSystemObject");
	try {
		fso.OpenTextFile(path, 8).Close();
		return false;
	} catch (e) {
		// 排他制御中でも同じ結果を返すが判別できない
	}

	// OS 判定
	// XP 以前は不要
	var oLocator = new ActiveXObject("WBemScripting.SWbemLocator");
	var oService = oLocator.ConnectServer();
	var os = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_OperatingSystem"));
	if (Number(os.item().Version.substring(0, 3)) < 6.0) {
		return false;
	}

	// ファイルの権限を確認
	var SE_DACL_AUTO_INHERITED = 0x0400;
	var permission = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_LogicalFileSecuritySetting Where Path='" + path.replace(/\\/g, "\\\\") + "'"));
	if (!permission.atEnd() && permission.item().ControlFlags & SE_DACL_AUTO_INHERITED) {
		return true;
	}

	return false;
}

// ファイル保存
function SaveToFile(path, doc) {
	var charset = "utf-8";
	switch (doc.Encoding) {
		case meEncodingUTF16LEBOM:
		case meEncodingUTF16LENoBOM:
		case meEncodingUTF16BEBOM:
		case meEncodingUTF16BENoBOM:  charset = "unicode";      break;
		case meEncodingUTF8BOM:
		case meEncodingUTF8NoBOM:     charset = "utf-8";        break;
		case meEncodingUTF7:          charset = "utf-7";        break;
		case meEncodingEUC:           charset = "euc-JP";       break;
		case meEncodingJIS:           charset = "iso-2022-jp";  break;
		case meEncodingShiftJIS:      charset = "shift-jis";    break;
	}

	var adodb = new ActiveXObject("ADODB.Stream");
	adodb.Charset = charset;
	adodb.Type = 2;
	adodb.Open();
	adodb.WriteText(doc.Text.replace(/\n/mg, NEWLINE_CODE));

	// BOM 削除処理
	if (doc.Encoding == meEncodingUTF8NoBOM) {
		adodb.Position = 0;
		adodb.Type = 1;
		adodb.Position = 3;
		var binary = adodb.Read();
		adodb.Close();

		// 新規ストリームに BOM を除いた文字列を書き込む
		adodb.Open();
		adodb.Write(binary);
	}
	adodb.SaveToFile(path, 2);
	adodb.Close();
};

// マークの更新
// すぐに反映されないので対処
function UpdateSavedMark(isSaved) {
	if (document.Saved != isSaved) {
		document.Saved = isSaved;
		var sel = document.selection;
		if (sel.GetActivePointX(mePosLogical) == 1 && sel.GetActivePointY(mePosLogical) == 1) {
			sel.CharLeft();
		} else {
			sel.CharLeft();
			sel.CharRight();
		}
	}
}

パターン2[編集]

副作用(制限)

  • 元に戻す、やり直しの履歴が削除される
#title="上書き保存"

// -----------------------------------------------------------------------------
// Overwrite.js
//
// UAC対応の上書き保存
//
// (C) ks
// http://merysmacro.seesaa.net/
// -----------------------------------------------------------------------------

// 『無題』は通常処理
if (!document.Name) {
	document.Save();
	Quit();
}

// 変更がない場合は保存しない
if (document.Saved) {
	Quit();
}

// ファイルがない場合は通常処理(Mery準拠)
var fso = new ActiveXObject("Scripting.FileSystemObject");
if (!fso.FileExists(document.FullName)) {
	document.Save();
	Quit();
}

// 書き込み禁止か取得
var file = fso.GetFile(document.FullName);
if (file.Attributes & 0x01) {
	Alert("このファイルは読み取り専用です");
	Quit();
}

// UAC の判定
if (!IsNeedUAC(document.FullName)) {
	document.Save();
	Quit();
}

var shell = new ActiveXObject("Wscript.Shell");
var folder = shell.ExpandEnvironmentStrings("%TEMP%");
var tempFilePath = fso.BuildPath(folder, document.Name);

// 保存前の状態を保持
var sel = document.selection;
var latestText = document.Text;
var sx = ScrollX, sy = ScrollY;
var tx = sel.GetTopPointX(mePosLogical), ty = sel.GetTopPointY(mePosLogical);
var bx = sel.GetBottomPointX(mePosLogical), by = sel.GetBottomPointY(mePosLogical);
var filePath = document.FullName;

// 一時ファイルに保存して UAC 対応ムーブ
document.Saved = true;
document.Save(tempFilePath);
var appShell = new ActiveXObject("Shell.Application");
appShell.ShellExecute("cmd.exe", '/c COPY /Y "' + tempFilePath +'" "' + filePath + '" & DEL "' + tempFilePath + '"', "", "runas", 2);

// ファイルムーブの完了待ち(最大 1 秒)
for (var i=0; i<50; i++) {
	Sleep(20);
	if (!fso.FileExists(tempFilePath)) {
		break;
	}
}

// ファイルを開き直す
// UACの昇格を拒否されていた場合は、エディタ上の内容だけ書き換え
editor.OpenFile(filePath);
var doc = editor.ActiveDocument
if (doc.Text != latestText) {
	doc.Text = latestText;
}
doc.Selection.SetActivePoint(mePosLogical, tx, ty);
doc.Selection.SetAnchorPoint(mePosLogical, bx, by);
ScrollX = sx; ScrollY = sy;


//==============================================================================
// 関数定義

// UAC が必要かを判定
function IsNeedUAC(path) {
	if (!path) {
		return false;
	}

	// 書き込み可能か確認
	var fso = new ActiveXObject("Scripting.FileSystemObject");
	try {
		fso.OpenTextFile(path, 8).Close();
		return false;
	} catch (e) {
		// 排他制御中でも同じ結果を返すが判別できない
	}

	// OS 判定
	// XP 以前は不要
	var oLocator = new ActiveXObject("WBemScripting.SWbemLocator");
	var oService = oLocator.ConnectServer();
	var os = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_OperatingSystem"));
	if (Number(os.item().Version.substring(0, 3)) < 6.0) {
		return false;
	}

	// ファイルの権限を確認
	var SE_DACL_AUTO_INHERITED = 0x0400;
	var permission = new Enumerator(oService.ExecQuery("SELECT * FROM Win32_LogicalFileSecuritySetting Where Path='" + path.replace(/\\/g, "\\\\") + "'"));
	if (!permission.atEnd() && permission.item().ControlFlags & SE_DACL_AUTO_INHERITED) {
		return true;
	}

	return false;
}

ご意見・ご要望[編集]

何かありましたら、右の [編集] から追記してください。対応するもかしれません。

スポンサーリンク