23
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

神InternetExplorerでバイナリファイルの書き込み

Posted at

こんにちわ。

皆さんは業務でInternetExplorerはお使いでしょうか。
弊社では、残念ながら未だIE11が社内標準として使われ続けています。

ES6が全滅な時点で、個人的には極力使いたくない負の遺産ですが...

文句を言っていても始まらないので、こうなったら開き直って使い倒してやろうと思います。

#IEと言えばActiveX
ご存知、WindowsにベッタリのAPIです。

開き直って使ってみて思ったのですが、本当に何でも出来るんですね。

// CMDオブジェクト呼出
const msWsh = new ActiveXObject("WScript.Shell");

// コマンド実行(同期)
msWsh.Run("foo", 0, true);

これでコマンドプロンプト打ち放題ですよ。

// FSオブジェクト呼出
const msFso = new ActiveXObject("Scripting.FileSystemObject");

// ファイル指定
const file = msFso.OpenTextFile("path", 2, true, -1);

// テキスト書込
file.Write("bar");

任意のディレクトリへファイル保存も簡単に出来ます。

ブラウザ側で実行防止設定があるとは言え、セキュリティとは一体...

#バイナリファイルを読み書き
さて本題。
テキストファイルは簡単に出来るんですけどね、バイナリファイルは小細工が必要です。

// ActiveXインスタンス用変数の確保
let msFso;
let msWsh;

// IE用
if(/trident/.exec(navigator.userAgent.toLowerCase())){
    msFso = new ActiveXObject("Scripting.FileSystemObject");
    msWsh = new ActiveXObject("WScript.Shell");
}

// ActiveXプロパティ
const msActiveX = {

    // 引数: コマンド文字列
    cmd: function(command){
        return msWsh.Run(command, 0, true);
    },

    // 引数: base64文字列, 出力ファイル名
    writer: function(base64, path){

        // msFso.GetSpecialFolder()は特殊ファイルパス取得メソッド
        // 2 => %temp%
        const temp = msFso.GetSpecialFolder(2) + "\\temp.tmp";

        // ファイルオブジェクト
        const file = msFso.OpenTextFile(temp, 2, true, -1);

        // base64書込
        file.Write(base64);
        file.Close();

        // base64 => binary
        this.cmd("certutil -f -decode " + temp + " " + path);
    }
}
HowToUse
const reader = new FileReader();
reader.onload = function(){
    msActiveX.writer(new String(reader.result).replace(/^.*?base64,/, ""), "c:\\myFile.zip");
}
reader.readAsDataURL(myBlob);

FSOでの読み書きは文字列しか出来ないので、一旦base64で保存する所がミソです。

後は、WSHでWindows標準搭載のcertutilコマンドを叩いてbase64 => binaryに変換すれば完成です。

#実業務で役立ちそうなオマケ
ブラウザ上で生成したファイルを纏めてOutlookに添付するアレ。
(やりたくないけど仕事でよくやるやつ)

JSZip.jsを使うと、良い感じに出来ます。
Encoding.jsを使うと、CSVなどを生成した場合、神Excelで読込可能なSJISに変換出来ます。

let msOutlook;

if(/trident/.exec(navigator.userAgent.toLowerCase())){
    msOutlook = new ActiveXObject("Outlook.Application");
}

const msActiveX = {

    // 引数: 添付ファイルパス
    mailer: function(path){

        // メールオブジェクト
        const mail = msOutlook.CreateItem(0);

        // ウィンドウを表示
        mail.Display();
        mail.GetInspector.WindowState = 2;

        // 本文の設定
        mail.To = "myaddr@example.jp";
        mail.Subject = "の件につきまして";
        mail.Body = "何卒宜しくお願い致します。";

        // 添付ファイル指定
        mail.Attachments.Add(path);
    }
}
HowToUse
//JSZip.jsとEncoding.jsを使った例

function toSjis(text){
    return Encoding.convert(text, {
        to: "SJIS",
        from: "AUTO",
        type: "array"
    });
}
const csvArray = toSjis(myTextUtf16);

const jszip = new JSZip();
jszip.file("申請書1.csv", csvArray, {binary: true});

jszip.generateAsync({type: "base64"})
    .then(function(body){
        const attach = "c:\\myFile.zip";
        msActiveX.writer(body, attach);
        msActiveX.mailer(attach);
    })
    .catch(function(error){
        return new Error(error);
    })

もう平成も終わろうとしているのに、こんなパワープレイがまかり通ってるのはおかしいよ!!!

#おわりに
とても悔しいけどWindows使ってる身からするとActiveX便利ですね...
SJISと神Excelは滅べ

23
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?