イネマルのプログラミング備忘録

趣味プログラマーのメモ

WSH JScript で、C# プログラムを実行する方法

はじめに

JScript から C# のソースをコンパイルする話
JScriptC# ソースを埋め込んで、コンパイル→実行 みたいなことができます。
ついでに、生成したC#プログラムから実行元のJScriptの関数を呼び出す機能をついでに用意。

前提

PowerShell 使う方が正攻法なのですが、
いろんな事情で、WSHを使用する必要がある場合の実装です。

サンプルが洗練されていないため、関連機能が詰め合わせ状態ですが、
とりあえず、コピペで実行できる想定のバッチを用意。

やっていることは、おおよそ下記の通り。

  • バッチからJScriptを実行
  • JScriptからC#ソースをビルド
  • 生成したプログラムを実行
    • JScriptのソースを読み込み
    • JScriptの関数を呼び出し
    • フォームを表示
  • 生成したプログラムを削除

実装

長いので折りたたみ

あとがき

備忘録なので、とりあえず動けば良いやくらいの実装。
やっていることは、何のひねりもなくビルドして実行なので、そこそこ力業だと思う。

C++ で、コマンドの標準出力を取得する方法(CreateProcessなし)

はじめに

Windows でコマンドを実行する際、標準出力を取得する方法です。
コンソール画面が表示されても問題ない場合、
もしくは、CUIプログラムで使用できる方法です。

前提

system 関数だけでは、標準出力が簡単に取得できません。
Windows 環境では、APIの CreateProcess を使用する方法が良く使用されますが、
Linux 環境などで使用される popen を使用した方がシンプルに実装できます。

標準エラーの対応は、行っていませんが、
表示したくない場合は、実行コマンド末尾に「 2>&1」を付けて標準出力にリダイレクトする等
適宜対応しましょう。

実装

あとがき

Windows では、popen が使用できないと思い込んでいましたが、
_popen の名前で、使用できるので、実装して備忘録行き。

WSH JScript をバッチに埋め込んだ際にコンソールウィンドウのPIDを取得する方法

はじめに

タイトルの通り、バッチファイルからWSH(cscript)を起動した際に
コンソールウィンドウのPIDを取得する方法です。

概要

WSHからアプリケーションを実行中に
コンソールウィンドウが閉じられると困るので、
コンソールウィンドウのプロセスを特定するために使用します。

実装

あとがき

JScript から C# を実行するときに
コンソールウィンドウの表示状態を操作するために使う実装です。
ニッチすぎるネタ。

【WSH】JScript で、多重起動判定

はじめに

WSHで多重起動判定する方法です。
できるだけ、スマートに実装したつもりです。

実装

サンプルは、shebang記法でバッチファイルにJScriptに埋め込みしていますが
普通に.jsでも動くはず。
Sleepで適当な時間待って、終了前に起動したものは多重起動判定されます。

判定方法は、WMIを使用して、実行ファイル名で検索をかけることで実現しています。
そのため、同名のバッチファイルが起動されていると誤検出し得るので、
ファイル名は、被らないようにしましょう。

あとがき

そこまで凝ったモノは要らない人向けです。
簡単な物であれば、5行程度で判定できるというネタでした。


C++ コマンドライン引数をstd::vectorに展開する方法

ちょっとしたメモ

使わなくても良いテクニックですが、どこかで使いそうなのでメモっときます。
用途があるとしたら、
vectorコンテナとしてコマンドラインをやり取りしたいときとかでしょうか?

実装

あとがき

エントリーポイントを int main(std::vector<std::string> args)
みたいに書けたら楽ですが、そういう横着はできません。

元ネタは、下記を参照。
stackoverflow.com

【Windows】バッチファイルで管理者権限を判定する方法 3種

バッチファイルで管理者権限を判定する方法 3種

Windowsのバッチファイルで管理者権限が必要な場合に
標準のコマンドで確かめる方法を調査したときの断片です。
以下、巷で使われている手法の3種です。

whoami コマンド

いろいろな方法がありますが、自分が普段使用している
whoami コマンドを使用する方法です。
whoami コマンドのprivオプションは、
ユーザーやグループに割り当てられた権限を表示します。
権限に「SeLoadDriverPrivilege」が含まれるかどうかで、管理者権限を判定します。

openfiles コマンド

openfiles コマンドは、管理者権限が必要なコマンドです。

> nul > 2>&1 で、標準出力を出さないようにしています。

net コマンド

session や file オプションは、管理者権限が必要なため判定が行えます。

あとがき

ちなみに、管理者権限に昇格させる方法は、
Powershell の -Verb runas が手っ取り早いです。

いつの間にか、Markdownが使えるようになっていたので、Markdownで書いてみたり。 やっぱりMarkdownは、書きやすい。

フォントファイルからフォント名を取得する

f:id:inemaru:20170611112448p:plain

目的

C++で、フォントファイルからフォント名(フォントファミリ名)を取得します。
対応フォーマットは、スタンダードに ttf, otf とします。

対応

結局のところ、バイナリから直接、フォント名を取得するのが高速だと思うので、
フォーマットを解析しながらフォント名を取得します。

既知の方法

今回は使用しない既知の方法としてGDIを使用した方法があります。

  • GDI+の「PrivateFontCollection」

GDIのインスタンスを起動させる必要があり
対応フォーマットは多種ですが、フォント名を取得するだけで使用するには低速です。

昔、この方法で実装しましたが、
「GDIの起動が低速」(+自分の実装ミスでバグ持ち)という問題があり、
かなり微妙でした。

  • GDI+の非公開API「GetFontResourceInfo」

高速に動作しますが取得した結果が、
英名だったり「 & 」で結合された結果が戻ったり仕様に不明点が多いです。
非公開APIなので最悪、突然使えなくなるかもしれないという危なっかしさもあります。

注意

勉強のついでの感覚で実装しているので、実用性は考慮していません。
また、バグとかあっても自己責任でお願いします。

準備

ブログにコードを載せるには量が多いので、ソースはアプロダに上げます。
フォントファイルからフォント名を取得.zip(フォントファイルからフォント名を取得.zip) ダウンロード | イネマルの備忘倉庫 | uploader.jpをダウンロードして
VS2015以降のコンソールプロジェクトに追加した状態で動く想定です。

プログラム

下記のように使用します。

int main()
{
	// ロケール設定
	std::locale::global(std::locale("japanese"));
	setlocale(LC_ALL, std::locale().c_str());

	// フォント名取得
	FontFamilyMap nameMap;
	if (GetFontFamilyName(L"./GenEiLateGo.otf", nameMap)) {
		std::wcout << L"英:" << nameMap[LANGUAGE_ID::LID_ENGLISH] << std::endl;
		std::wcout << L"日:" << nameMap[LANGUAGE_ID::LID_JAPANESE] << std::endl;
	}

	// 一時停止
	system("pause");

	return 0;
}

出力結果

英:GenEi LateGo
日:源暎ラテゴ
続行するには何かキーを押してください . . .

使用させて頂いたもの

  • フォント

源暎フォント置き場 - 御琥祢屋

  • 参考サイト

d.hatena.ne.jp
www.codeguru.com

あとがき

経緯について
プログラム中にインストールしていないフォントを
使用したいタイミングがあったとして
Windows環境だと、自プロセスで使用するフォントを追加する場合に、
AddFontResourceExを使用すると思います。

追加には、フォントファイルのパスが分かれば問題ないですが、
いざ使用する時、フォント名を指定する必要があります。

フォント名を明示しないといけないという柔軟さのなさを回避するには、
フォント名がフォントファイルから分かった方が都合が良いということで、
対応した結果を備忘録行き。