おととい,昨日と,Win32 サービスとして動作する印刷アプリケーションについていろいろ悩んでみました。なんとか解決したかに見えたのに・・・
部長が帰った後だったんだけど,いよいよ Release モードでコンパイルして,本番さながらのテストをしようとしました。すると・・・
また動かなくなってるし!?
まったく同じ症状です。印刷キューには一瞬溜まるんだけど,一瞬にして消化され,しかし実際には何も印刷されません。
しかし私自身は最近調子がよいらしく,ここでもプログラマの勘が発動。テストパターンを印刷してみると,きちんと“何も印刷されません”。IE や WORD で適当なモノを印刷しようとしてみても,やはりちゃーんと“何も印刷されません”。
実は部長のマシンにはファイアウォールが入っているらしいのですが,その影響で私や他の人のマシンはネットワークの利用に制限がかかってしまうようなのです。それでは困るということで,少なくとも部長は昼間,ファイアウォールを有効にしていません。しかし帰る間際にはその自己主張の激しい防火壁を有効にするのでしょう。今夜の印刷アプリケーションの障害も,それが原因に違いありません。
ということで,今日は帰ることにしました。おつかれさま。
疲労度:0
2002-07-27 の雑記で 100 回記念だったんスねー。すっかり忘れてました。
他者との協力は脳内の快楽が動機?──協力行動を説明する新理論(hotwired japan)
ヒトってのはわりと社会的な生物であって,社会生活を営むには当然,他者との協調が不可欠なわけです。しかしどうしてそれが実現できているのか,理論的には説明がつきませんでした。それが「囚人のジレンマ」や,もっと突き詰めて「社会的ジレンマ」と呼ばれる問題。
なるほどねー。協力するっていうのは理論的な思考を経るんじゃなくて,脳みそのキモチよさによって実現されているのでした。究極の功利主義者は何のためらいもなくコジキにお金をやると言われていますが,その行動に,特に理論的な説明は必要なかったわけです。・・・と結論を急ぐわけには行きませんけどね。まだ入り口,かな。
これはあれだ,ともすると,経済学にも大きな波紋が広がりますよ。西山賢一先生あたりが喜んで飛びつくに違いありません。絶対。
昨日に引き続き,Win32(NT)サービスとして印刷アプリケーションを作った時に,まったく動かないという問題を扱います。ていうか,解決できました。
例えば Windows2000 だったら,私がマシンの電源を入れてボーっとしていると何時の間にかいつものデスクトップが表示されていたりします。よく知らないんだけど,デフォルトで何かのユーザに自動的にログオンされるんですよね? 画面左下の「スタート」ボタンを押して 「Windows の終了」「ログアウト」とかすると,ここでやっと Windows2000 のログイン画面にお目にかかることになります。
それからプリンタのこともお話しないと。プリンタは部長のマシンに接続されています。そして私のマシンと部長のマシンはごっつい機械 ( HUB ってやつ? ) を介した LAN ケーブルで繋がっています。これはいわゆる「ネットワークプリンタ」てやつですか。
私のマシン上で何かを印刷するなら,必ず「エクスプローラ」で部長の共有フォルダを覗こうとしなければなりません。そこでユーザー名「kaisya_id」とパスワード「kaisya_pass」を入力して「OK」,晴れて私のマシン全体がネットワーク上に仲間入りをするらしいのです。
私のマシンは,まさにそんな環境です。
今日も元気にバグフィクスだーと,動かない私のアプリケーションを動かしました。印刷キューには一瞬登録されます。そして一瞬にして消化されます。しかし案の定プリンタは何も印刷をしません。
そこでふと気付いたのが印刷キューにある「所有者」の欄。登録された瞬間,そこには "ANONYMOUS LOGON" と表示されています。むむむ,ここは・・・?
気持ちよい程の「プログラマの勘」の発動っ振りです。よーしよし,確実に印刷に成功することを確認できている,同様のプログラムを持ってきました。そして印刷を実行。キューを見てみると・・・「所有者」の欄には "kaisya_id" と出ているではありませんか。
ここだーっ!!
「設定」「コントロールパネル」「管理ツール」「サービス」と下り,件のサービスを選択,プロパティのダイアログを出して「ログオン」タブを前面に出します。そして「アカウント」ラジオボタンを選択し,「参照(B)...」・・・
".\kaisya_id" あったーっ♪
いかにもソレっぽいでしょう? 実際,これで正解な模様。パスワードに "kaisya_pass" と打ち込んで,サービスを再起動。こうして長き ( 2 日 ) に渡る闘いは 勝利 で幕を閉じました。
今日はいい夢を見たいです。おわり。
疲労度:99999
昨日の雑記は "2002-07-27" とか日付をふってたりするし。なんか,こう,絶好調かもわからんね。
問題にぶち当たりました。Google でもめぼしい情報が引っかからなかったので,研究あるのみです。とりあえず私がやった苦労は皆さんがしなくてもよいように,このような雑記でまとめて Google などで検索して見つけ出して欲しい,というのがこの雑記のコンセプト。検索エンジンに引っかかりやすいように,文章の各所にキーワードを並べるのに必死になってます。
Win32(NT)サービス内で印刷処理を行おうとしている最中ですが,なぜか印刷してくれません。普通にコンソールアプリケーションとして動かせば印刷してくれるのにね。
CreateDC,StartDoc すると,ちゃんとキューには溜まるんですよね。そしてスプーラが実際に印刷を開始して・・くれないまま,キューから削除されてしまいます。
これはきっとあれだ。「サービス」は,どのユーザーが Windows にログオンしなくとも稼動するアプリケーションです ( ですよね? )。そして私がテスト用に用いているプリンタはネットワーク上のプリンタ。私のアカウント kuri_minima で Windows にログオンし,さらにネットワーク上のプリンタにユーザー名 kaisya_id とパスワード kaisya_pass で接続したって,そうやって得た権限がサービスアプリケーションに伝わっていないのでしょう。
サービスアプリケーション内でも,kaisya_id と kaisya_pass で何とかしてネットワークに接続しなければならないのかな? 明日はこのあたりで格闘するハメになりそうです。というわけで,このお話は続きます。
疲労度:79
汗がウザい日は,全身にタルカム・パウダーをまぶせばよかったんですね。制汗剤とは違って出すべきモノを抑えるわけではないんで,そんなに非健康的でもなさそうだし。
・・・夏の日中,四畳半の部屋,真っ白い粉まみれで頑張っている 24 歳九州男児・・・うぇっ・・・
結局,以前にちょこっと紹介した VisualC TechTips に,GetWindowModuleFileName 関数と同様の動作をする関数が掲載されているのを見つけました。「ウィンドウハンドルから .EXE 名を取得するには?」ですね。ヤケクソに面倒な処理である上に,Windows NT 4.0 では PSAPI.DLL が別途必要。ここらへんが,Windows の設計がアレだと言われる部分だと思います。
そこに行き着く前に,いろんな試行錯誤をしたんですよ。「私の開発環境には GetWindowModuleFileName 関数の定義は存在しなくとも,きっと WindowsMe の kernel32.dll や user32.dll にはエントリポイントが存在しているに違いない。それを GetProcAddress で取得すれば問題解決だー」とかね。
// 注意:このコードは何の役にも立たないどころか
// どこかがおかしいようです
#define DLL_NAME "kernel32.dll"
#define PROC_NAME "GetWindowModuleFileName"
UINT exGetWindowModuleFileName(HWND win, LPTSTR buf, UINT len) {
typedef UINT (*type_GetWindowModuleFileName)(HWND,LPTSTR,UINT);
static type_GetWindowModuleFileName pFunc = 0;
if (pFunc == 0) {
HANDLE hinst = ::GetModuleHandle(DLL_NAME);
if (hinst == 0) { // **
puts("failed 1");
return 0;
}
pFunc = (type_GetWindowModuleFileName)
::GetProcAddress(hinst, PROC_NAME);
// ::FreeLibrary(hinst); だめだめだめ……
}
if (pFunc == 0) { // **
puts("failed 2");
return 0;
}
return (*pFunc)(win, buf, len);
}
2 箇所あるコメント // ** はエラートラップの部分。この周辺で問題が発生しています。GetProcAddress が失敗して `failed 2' が出力されるならまだ分かりますが,今日は違いました。なんと GetModuleHandle が失敗しやがります。 このコードは,`kernel32.dll' のモジュールハンドルを得るための非常にありふれた書き方。MS 推奨なのです。どうして由緒正しきこのコードが失敗しますか?
このネタ,しばらく考えてみようと思います。
疲労度:58
掲示板にて yu さんからご指摘。GetModuleHandle() で得たハンドルは,参照カウントがインクリメントされていません。それなのに FreeLibrary() で参照カウントをデクリメントしてしまうと,そりゃ何が起こるか分かったもんじゃありません。
サディスティック・ミカ・バンドが新アルバムを発表するよりももっと驚くべき事が起こるかも知れないのです。
ジャイやんの中の人が,深夜アニメとかオパイゲームに出演するくらい驚くべき事が。
あーもう(;´Д`)自分,一度くらい名誉毀損で訴えられろ。
本当はポインタのちょっとしたギャグをかまして今日の雑記は終わろうかなと思ってたんですが,サイトの巡回中に思わぬネタを拾ってしまったので,しばらくこのネタでいこうと思います。
ネタというのは,タイトルのまんま「全プロセスのファイル名を得るには?」です。つまり現在 Windows システム上で稼動しているプロセスは何という実行ファイル名なのか? というワケですね。
どうやらこんな便利な API があるようです。MSDN からの引用 ( URL 長いよ・・ ):
GetWindowModuleFileName Function
The GetWindowModuleFileName function retrieves the full path and file name of the module associated with the specified window handle.
ほほほう。ひとまずこんなコードを組んでみました。
#include <windows.h>
#include <stdio.h>
BOOL enumModuleFileNamesProc(HWND win, LPARAM lp) {
char buf[256];
UINT r = ::GetWindowModuleFileName(win, buf, 255);
buf[r] = 0;
puts(buf);
return 1;
}
void enumModuleFileNames() {
::EnumWindows((WNDENUMPROC)enumModuleFileNamesProc, 0);
}
int main() {
enumModuleFileNames();
return 0;
}
そしてビルド。・・・すると,コンパイラ怒る:
コンパイラ「GetWindowModuleFileName:そんな関数無ぇよ」
えっ・・・と,とりあえず
UINT
GetWindowModuleFileName(HWND,
LPTSTR,
UINT);
などと自分で宣言しちゃって,再度ビルド。そしてリンカ怒る:
リンカ「GetWindowModuleFileName:無ぇってば」
こまるっ・・・。
そういえば私は家で使う VisualStudio のアップデートをした事がないんですが・・・それが原因かも? その昔,GetWindowModuleFileName は隠し API だったとか,まともに動かないとか,いろんな怪しい噂が web 上で飛び交っていました。。。
とりあえずとりあえず,このお話は続きます。
最高速度 300km/h を誇る新幹線「のぞみ」乗ってきました。始発で博多へ,そしてその日最後の「のぞみ」で東京へ戻り,最終電車でアパート近くの駅までってか。人類は楽をするためにいろいろと技術を積み重ねてきたはずなのに,中を覗いてみると このていたらく。 あはは。
正直な感想:「150km/h も 300km/h も判らんね」。あまりにも通常時に体験する速度とはかけ離れているため,「速い」以外の感想が出てこないのです。きっと日本国民の 1 万人に一人くらいは「のぞみ」に乗り飽きてて,その中の 10 人に一人は 150km/h と 300km/h の違いが判るんだろうな。少しうらやましい気がしました。
ところで,これは仕様っすか? それともバグ? ・・・帰りのキップとして博多〜東京の乗車券with特急券を買い,「のぞみ」で東京駅に到着,そのまま「山手線乗り換え口」なるものを通過し,何だか分からないまま山手線上の某駅に到着。この時点で山手線を利用した料金は支払われていません。しかし,乗車券with特急券を乗り越し精算機に通しても「改札のおいさんに言え」,改札のおいさんに尋ねると「このまま出ていいっすよ」。言われるままに改札を出ましたが何か?
今日も日記風でした。
疲労度:(__int64)~0
IE がブラウザのデファクトスタンダードに成り上がってから随分とたつんですが,近頃では IE もいわゆる「標準」に準拠する動きが出てきたと聞きました。細かい部分では,DOCTYPE 等の違いによってレンダリングアルゴリズムを替えたりするらしいですね ( ハッキリとした違いを目の当たりにしたことはあまりないんですが ) 。こういう動きは手放しで喜ぶべきだと思いました。充分に標準に準拠しているソフトウェア間ならば,データの互換性が期待できます。
ところで,これはズバリ,どうなんでしょうね?
#include <stdio.h>
int foo(int a, int b) {
return a + b;
}
int main() {
int (*pFoo)(int, int) = foo;
printf("%d\n", pFoo (1, 2) );
printf("%d\n", (*pFoo)(3, 4) );
return 0;
}
つまり関数ポインタにより指し示された関数の動かし方です。VC++5.0 でも gcc でもコンパイルに成功,期待通りに動作してしまいました。
多くのサイトでは後者のようなちょっと煩雑な書き方,(*pFoo) のみで解説をしていたりします。`K&R 本' でも同様にね。しかし多くのコンパイラでは前者のような呼び出し方でも期待通りの動作をさせてくれる模様。
おっと,これを書きながらより詳細を調べていると,こんな書き方も発見。
int (*pFoo)(int, int) = &foo;
関数名の前に & をつけ,ポインタを代入していることを強調しています。これでも VC++5.0,gcc ともに何ら問題は起こりませんでした。
このあたり,徹底的に なんでもあり な気がしてきました・・・。それでいいのか!?
疲労度:76
雨が降ってます。これで明日晴れてしまうとまさに不快指数地獄。東京ではただ生存するだけでも命がけです。
そんな過酷な自然環境にも負けず,私は今日もカッチョいい Abstract な Tree クラスを考えていました。STL の vector みたいなコンテナクラスのように,テンプレートで型を指定してやることで,どんな型からでもツリークラスを生成できるやつですね。・・・本当はやらないといけない仕事がいくつかあるんだけど,お構いなしです。
そういえば最近の CPPLL では多重継承の話題が盛ん。その「多重継承」なるものを利用して
template<typename T>
class AbstractTree : public T, List<T*> {
};
お,これだけで立派な仮想 tree クラスが出来ちゃった? ここで List<T*> は一般的なコンテナクラスを指します。素直に vector て書いた方がよかったかな・・・。
木構造といえば XML が大流行。でも解説するのは面倒なので,ここではディレクトリ/ファイルの構造にこの tree クラスを適用させてみます。
// 基本的なディレクトリ/ファイルを示すクラス
class AbstractFileItem {
public:
// ディレクトリ? ファイル?
virtual bool isDirectory() const = 0;
};
// ディレクトリ .. AbstractFileItem であり,そのリストでもある
class Directory : public AbstractTree<AbstractFileItem> {
public:
bool isDirectory() const { return true; }
}
// ファイル .. 木構造ではない
class File : public AbstractFileItem {
public:
bool isDirectory() const { return false; }
};
うーん,なんだかこのまま成功しそうな予感。テンプレートの使い方がちょっとトリッキーですが,しばらくこれを使ってみようと思いました。
疲労度:25
cppll の議論からのインスピレーション:
class Tom : public Father, Mother {};
class Yukari : public Father, Mother {};
class Fantasy : public Tom, virtual Yukari {};
私はもうダメかもわからんね(;´Д`)
F11 キーを押すと,こうなります。
Opera でも IE でも当たり前についてる機能だし,当然 Mozilla でも以前からついてたらしいです。確かにメニューにも堂々とあるのに,気付かなかったー。
いかんせん情報が少ないんで辟易。「サービス」じゃなくてもっとオサレでナイスでイカスな名前を付けてくれれば,ネット上で情報を検索するのにも楽だったんですが,うーん,なんとかならなかったのかなー。ちなみに私は「半荘のプログラマ向けペイジにようこそ。」の記事で勉強しました。2002年7月現在では「その他技術っぽいこと -> WindowsNT/2000に関すること -> 昔書いたWin32(NT)プログラミングノウハウ集」で,目的の記事にたどり着きます。
その「サービス」として動いているアプリケーションのカレントディレクトリ,Windows2000 では `WINNT\SYSTEM32\' である事を知りました。特別にディレクトリも何も指定せずに CreateFile を実行すると,前述のディレクトリにファイルが生成されたりするわけですね。
ん,今日はそれだけです。へへへ。
疲労度:53
東京で生きのびるための鉄則第一条:夏はクッキーを食べてはいけない! 世界的にも異常な湿度を誇る魅惑の街 TOKYO,わずか 22 時間でクッキーがヘニャヘニャになります。
最近雑記が失速気味ですが,記録的な異常気温に生命の危機を感じているからです。今日もちょっとページを紹介するだけで終わっちゃえ。
これは何かというと,んー,何のクラスなんでしょうね? ninja2 とかいうパッケージの何からしいんですが,正体不明。
笑っちゃうのが msg メソッド。可変個の引数を取ることを実現するために,ニンとも強烈な手段を用いています。結果,多重に定義された msg は 68 個。
なぜ Object のリストを渡しませんか。
室内温度:38 度
http://3.141592653589793238462643383279502884197169399375105820974944592.jp/
今日はちょっと趣向を変えて,URL をそのまま紹介してみました。実在します。ジョークではありません。というより,ジョークを挟む隙がありません。
私はここで「あれ?」と疑問に感じ,RFC1738 を読み返して見ました,ドメイン名は数字だらけでよかったんだっけ?
httpurl = "http://" hostport [ "/" hpath [ "?" search ]] hostport = host [ ":" port ] host = hostname | hostnumber hostname = *[ domainlabel "." ] toplabel domainlabel = alphadigit | alphadigit *[ alphadigit | "-" ] alphadigit
数字,アルファベット,ハイフンの組み合わせで,前後がハイフンで始まったり終わったりしていなければ何でもよいようです。あーよかった。ところで
hostname = *[ domainlabel "." ] toplabel
これはつまり,トップレベルドメインしかなくても URL になり得る事を意味しますか? http://com/ とか?