windowsサービスのapacheでtracを動かす
以下の環境変数の設定がきちんとされてるかチェック
- PYTHONHOME
- SVN_HOME
- DIFFUTILS_HOME
- APR_ICONV_PATH
- PATH
make_obcallback: could not import mod_python.apache
とか出ることがある。
以下の環境変数の設定がきちんとされてるかチェック
make_obcallback: could not import mod_python.apache
とか出ることがある。
1 スレッド状態 (thread state) とグローバルインタプリタロック (global interpreter lock)
の日本語も英語も理解しづらかったので今日理解したことを俺語でメモ
Pythonのマルチスレッド実装は擬似マルチスレッド。ネイティブコードレベルでシングルであるかマルチであるかにはかかわらず。
Pythonレベルではひとつのスレッド同期用フラグ(グローバルインタプリタロック)があって、このロックを取得できたスレッドだけがコードを実行できる。
このロックはバイトコード100個分とブロックする可能性のある操作の前を目安に自動的に解放されて、次のスレッドが獲得できるようになっている。
つまり、Pythonで管理されてるスレッド群がOSレベルで本当に同時に実行されることはない。(んだとおもう)
んで、Pythonの中だけで完結してるときはこんなことを知らなくてもいいんだけど、Cで拡張しようとするとこの仕組みに参加しなければならない。
まず初めに必要なのがグローバルインタプリタロックの初期化。
void PyEval_InitThreads()Pythonインタプリタが走り始める最初のメインスレッドがこれを実行しなきゃいけない。
これを実行するとグローバルインタプリタロックが初期化されて、メインスレッドがその所有者となる。
ちなみにここで出てくる話はPython/C双方ともに一つのスレッドしか使わないのであればまったく関係ない。PyEval_InitThreadsも含め、以降に出てくるAPIは全て関係がない。
が、pythonの中でスレッドが作られているのならCのコードがPythonを起動したメインスレッドからのコールバックで動く場合でも以降のAPIは必要となる。
が、その場合はPyEval_InitThreadsは必要ない。Pythonの中で初めて新しいスレッドが作られるときに自動的にPyEval_InitThreadsされるからである。
PyEval_InitThreadsが必要となるのはPythonコード内で初めて新しいスレッドが作られるのよりも前に以降のAPIを使いたいときとなる。
スレッドのロックに関するたぶん全てのAPIがグローバルインタプリタロックを必要として、それを初期化するのがPyEval_InitThreadsなので。
スレッドのロックAPIを使う人は全てのAPIより前でPyEval_InitThreads()を呼んどいたほうがいいだろう。
次に必要なのがPythonAPIを使うスレッドの初期化と解放。
先に書いたとおり、CのスレッドがPythonAPIを使うときにはPythonのスレッド管理の仕組みに自身のスレッドを参加させなければならない。
CのスレッドをPythonのスレッド管理の仕組みに参加させるには、スレッド状態オブジェクトを作ってスレッドに関連付ける必要がある。
このスレッド状態オブジェクトを扱うときの流れはPythonのドキュメントにあるサンプルコードを引用すると以下のようになる。
PyThreadState *tstate; PyObject *result; /* interp is your reference to an interpreter object. */ tstate = PyThreadState_New(interp); PyEval_AcquireThread(tstate); /* Perform Python actions here. */ result = CallSomeFunction(); /* evaluate result */ /* Release the thread. No Python API allowed beyond this point. */ PyEval_ReleaseThread(tstate); /* You can either delete the thread state, or save it until you need it the next time. */ PyThreadState_Delete(tstate);
スレッド状態オブジェクトはPyThreadState_Newでつくる。
PyThreadState* PyThreadState_New( PyInterpreterState *interp )
指定したインタプリタオブジェクトに属する新たなスレッド状態オブジェクトを生成します。インタプリタロックを保持しておく必要はありませんが、この関数を次々に呼び出す必要がある場合には保持しておいたほうがよいでしょう。
PyThreadState_Newの引数には先のインタプリタ状態オブジェクトのインスタンスへのポインタが必要となる。 このポインタを取得するには以下の方法がある。
PyThreadStateを取得するAPIにはPyThreadState_Get()などがある。
PyThreadState* PyThreadState_Get()
現在のスレッド状態を返します。インタプリタロックを保持していなければなりません。現在のスレッド状態が NULLなら、(呼び出し側が NULLチェックをしなくてすむように) この関数は致命的エラーを起こすようになっています。
つまり、Pythonで管理されているスレッドでしか使えない。
PyInterpreterState* PyInterpreterState_New()
新しいインタプリタ状態オブジェクトを生成します。インタプリタロックを保持しておく必要はありませんが、この関数を次々に呼び出す必要がある場合には保持しておいたほうがよいでしょう。
void PyInterpreterState_Clear(PyInterpreterState *interp)インタプリタ状態オブジェクト内の全ての情報をリセットします。インタプリタロックを保持していなければなりません。
void PyInterpreterState_Delete(PyInterpreterState *interp)インタプリタ状態オブジェクトを破壊します。インタプリタロックを保持しておく必要はありません。インタプリタ状態はPyInterpreterState_Clear() であらかじめリセットしておかなければなりません。
PyThreadState_Getを使うならインタプリタロックを持っている必要がある。インタプリタロックの取得と解放には次のAPIを使う。
void PyEval_AcquireLock()グローバルインタプリタロックを獲得します。ロックは前もって作成されていなければなりません。この関数を呼び出したスレッドがすでにロックを獲得している場合、デッドロックに陥ります。この関数はコンパイル時にスレッドサポートを無効化すると利用できません。
void PyEval_ReleaseLock()グローバルインタプリタロックを解放します。ロックは前もって作成されていなければなりません。この関数はコンパイル時にスレッドサポートを無効化すると利用できません。
多分上のAPIはスレッドがPython管理下にないと使えない。
また、通常PythonAPIを使うようなCコードのエントリポイントではPythonのスレッド管理下にあり、グローバルインタプリタロックを持っていることが多そう。
ということからPython管理下のスレッドがインタプリタ状態オブジェクトを取得して、それをこれからPython管理下に入れたいスレッドに渡して、そのスレッドがPyThreadState_Newしてスレッド状態オブジェクトを作る、というステップを踏むことになると思う。もしくはPyThreadState_NewするたびにPyInterpreterState_Newするか。
PyThreadState_Newしてスレッド状態オブジェクトができたらPyEval_AcquireThreadでスレッドに関連付ける。
void PyEval_AcquireThread( PyThreadState *tstate )グローバルインタプリタロックを取得して、この関数を実行したスレッドに引数のスレッド状態オブジェクトを関連付ける。
グローバルインタプリタロックを獲得し、現在のスレッド状態を tstate に設定します。tstate は NULLであってはなりません。ロックはあらかじめ作成されていなければなりません。この関数を呼び出したスレッドがすでにロックを獲得している場合、デッドロックに陥ります。この関数はコンパイル時にスレッドサポートを無効化すると利用できません。
PyEval_AcquireThreadの実行直後からグローバルインタプリタロックはこのスレッドのものである。
PythonAPIをいじる処理が終わったらPyEval_ReleaseThreadする。
void PyEval_ReleaseThread( PyThreadState *tstate )引数のスレッド状態オブジェクトがこの関数を実行したスレッドに関連付けられていたら関連付けを解放し、グローバルインタプリタロックを解放する。
現在のスレッド状態をリセットして NULL にし、グローバルインタプリタロックを解放します。ロックはあらかじめ作成されていなければならず、かつ現在のスレッドが保持していなければなりません。tstate は NULLであってはなりませんが、その値が現在のスレッド状態を表現しているかどうかを調べるためにだけ使われます -- もしそうでなければ、致命的エラーが報告されます。この関数はコンパイル時にスレッドサポートを無効化すると利用できません。
ここで再び先のサンプルコードを見返してみる。
/* Release the thread. No Python API allowed beyond this point. */ PyEval_ReleaseThread(tstate); /* You can either delete the thread state, or save it until you need it the next time. */ PyThreadState_Delete(tstate);
PyThreadState_Deleteではいらなくなったスレッド状態オブジェクトを削除できる。
void PyThreadState_Delete( PyThreadState *tstate )スレッド状態オブジェクトを破壊します。インタプリタロックを保持していなければなりません。スレッド状態はPyThreadState_Clear() であらかじめリセットしておかなければなりません。
ここでへんなのはPyEval_ReleaseThreadでグローバルインタプリタロックを解放しているはずなのに、グローバルインタプリタロックを持っていないと呼べないPyThreadState_Deleteを呼んでいるところ。
インタプリタロックとグローバルインタプリタロックは別なのか?とも思ったけどそれもたぶん違う。ていうかそもそもPyThreadState_Clearしてない。
void PyThreadState_Clear( PyThreadState *tstate )スレッド状態オブジェクト内の全ての情報をリセットします。インタプリタロックを保持していなければなりません。
多分ドキュメントが最後のステップをいろいろ省略してるんじゃないかと。その辺の流れをきちんと整理してみると以下のようになる。
ReleaseThreadした後、いらなくなったスレッド状態オブジェクトを削除したいときはスレッドの開始時にPython管理下のスレッドからインタプリタ状態オブジェクトをもらったように、今度はPython管理下のスレッドにいらなくなったスレッド状態オブジェクトのポインタを渡し、そのスレッドでグローバルインタプリタロックを取得している状態で、PyThreadState_Clearし、PyThreadState_Deleteする。
たとえばPython管理下に入ったCスレッドでネットにアクセスしてデータをダウンロードする処理をしたいときその間ずっとグローバルインタプリタロックを握りっぱなしだと、たとえPythonのコードがマルチスレッドで書かれていてもそれら全てのスレッドがブロックしてしまう。
そこでダウンロードする前のPythonAPIを使い終わった時点でグローバルインタプリタロックを手放し、ダウンロードが終わったあとでPythonAPIを使う前にもう一度グローバルインタプリタロックを取得しなおす必要がある。
それらをするのが
Py_BEGIN_ALLOW_THREADS ...ブロックが起きるような何らかの I/O 操作... Py_END_ALLOW_THREADS
というマクロ。 これは
PyThreadState *_save; _save = PyEval_SaveThread(); ...ブロックが起きるような何らかの I/O 操作... PyEval_RestoreThread(_save);
というコードがマクロ化されたもの。
PyThreadState *_save;
_save = PyThreadState_Swap(
NULL
);
PyEval_ReleaseLock();
...ブロックが起きるような何らかの I/O 操作...
PyEval_AcquireLock();
PyThreadState_Swap(_save);
という書き方もできるが、errnoが退避されずロックを手放してもう一度獲得したときに変更されていたり、pythonインタプリタのスレッドサポートが無効の場合そもそもPyEval_ReleaseLock/PyEval_AcquireLockがロック操作をしないのだとか。とりあえずPy_BEGIN_ALLOW_THREADS~Py_END_ALLOW_THREADSしとけばよさそう。
PyThreadState* PyEval_SaveThread()
(インタプリタロックが生成されていて、スレッドサポートが有効の場合) インタプリタロックを解放して、スレッド状態を NULLにし、以前のスレッド状態 (NULLにはなりません) を返します。ロックがすでに生成されている場合、現在のスレッドがロックを獲得していなければなりません。
void PyEval_RestoreThread( PyThreadState *tstate)(インタプリタロックが生成されていて、スレッドサポートが有効の場合) インタプリタロックを獲得して、現在のスレッド状態を tstate に設定します。tstate は NULLであってはなりません。この関数を呼び出したスレッドがすでにロックを獲得している場合、デッドロックに陥ります。 (この関数はコンパイル時にスレッドサポートを無効化すると利用できません。)
という素敵APIも登場していた。
どうもこれを使うとPyGILState_EnsureからPyGILState_Releaseまでの間で今まであったややこしいことを忘れてPythonAPIを使えるようになるらしい。
んで、これは以前と変わらずに一時的にロックを手放したいときはPy_BEGIN_ALLOW_THREADS~Py_END_ALLOW_THREADSとする。
ここまでの内容を理解した上でPyGILState_Ensure~PyGILState_ReleaseとPy_BEGIN_ALLOW_THREADS~Py_END_ALLOW_THREADSすれば完璧?
PyGILState_STATE PyGILState_Ensure()
Pythonの状態やスレッドロックに関わらず、実行中スレッドでPython C APIの呼び出しが可能となるようにします。この関数はスレッド内で何度でも呼び出すことができますが、必ず全ての呼び出しに対応して PyGILState_Release()を呼び出す必要があります。
通常、PyGILState_Ensure()呼び出しと PyGILState_Release()呼び出しの間でこれ以外のスレッド関連API を使用することができますが、Release()の前にスレッド状態は復元されていなければなりません。通常のPy_BEGIN_ALLOW_THREADSマクロと Py_END_ALLOW_THREADSも使用することができます。
戻り値はPyGILState_Acquire()呼び出し時のスレッド状態を隠蔽した"ハンドル"で、PyGILState_Release()に渡してPythonを同じ状態に保たなければなりません。再起呼び出しも可能ですが、ハンドルを共有することはできません - それぞれのPyGILState_Ensure呼び出しでハンドルを保存し、対応するPyGILState_Release呼び出しで渡してください。
関数から復帰したとき、実行中のスレッドはGILを所有しています。処理の失敗は致命的なエラーです。
バージョン 2.3 で 新たに追加 された仕様です。
void PyGILState_Release( PyGILState_STATE)獲得したすべてのリソースを開放します。この関数を呼び出すと、Pythonの状態は対応するPyGILState_Ensureを呼び出す前と同じとなります。(通常、この状態は呼び出し元でははわかりませんので、GILState APIを利用するようにしてください。)
PyGILState_Ensure()を呼び出す場合は、必ず同一スレッド内で対応するPyGILState_Release()を呼び出してください。 バージョン 2.3 で 新たに追加 された仕様です。
以上、完璧に超意訳。
間違ってても責任負えませんっていうか間違ってたら教えてくださいm(__)m
Webサービスのサイトに写真とかを送信するのを自動化するにはどうするか、的な話。
最初はIEとJavaScriptで適当に送ってみようと思ったんだけどセキュリティがきつくなってて無理でした。というわけでpythonを使うことに。が、pythonもデフォルトではmultipart/form-dataはサポートしてない。ので、結局のところHTTPリクエストを自分でがりがり書くしかない。んでよくよく調べてたらurllib2をかっこよく拡張してる人を発見。
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306/
このスレッドの一番最後のコメント。
http://odin.himinbi.org/MultipartPostHandler.py
このMultipartPostHandler.pyを以下のように使うとurlとパラメータ渡すだけで通信できる。
cookies = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies),
MultipartPostHandler.MultipartPostHandler)
params = { "username" : "bob", "password" : "riviera",
"file" : open("filename", "rb") }
opener.open("http://wwww.bobsite.com/upload/", params)
ちなみにこのMultipartPostHandlerをハンドラに加えるとopenの第二引数のエンコードを自動的にやってくれる。
ブックマークレットです。タイトルのまんまです。
登録したいときはたいていそのページを読み終わってないことが多くて、デフォルトのブックマークレットだとはてなに飛んでしまって続きが読めないので別ウインドウにしてみました。
window.openしただけだから1エントリにするのも何だけどPC再インストしたときにまた書くのがめんどくさいからUP
これでそのページの動画をダウンロードするダイアログが開きます。(ダウンロードページを開くのではなくて直接落とし始めます。)
常にファイル名がget_videoになってしまいますが、ファイルの拡張子は.flvという形式です。
ちなみにgoogle videoからAVIで直ダウンロードするブックマークレットは
Google Operating System: Download Google Videos As AVI Files
にあります。
(Ref: Going My Way: Google VideoからAVI形式でダウンロード可能なBookmarklet )
さらにちなみに、VideoDownloader(直リンじゃないけどやたら多数の動画サイトからダウンロードするページを作れる)のブックマークレットは以下
思わず作ってみました。
IE系ブラウザ(IE6,Sleipnir,glucose,...)でみてるWebページのリンクにショートカットをつけて、Altキーを押しながらショートカットを入力することでリンクを飛べるようになります。
ほかにはAlt+上で上のディレクトリに移動したり、マウス右クリックしながら右にドラッグで進む、左にドラッグで戻る、といったマウスジェスチャーがIEでも可能になります。
FireFoxにおけるGreaseMonkeyみたいなことをして実装してます。
ほとんど思いつきで作ったんでかゆいところに手が届いてないですが、機会があったらもっと使えるものにしたいなーと。
「このコンピューターで利用できるターミナル サーバー クライアント ライセンスがないため、リモートセッションは切断されました。サーバー管理者に問い合わせてください。」
というのが出たときはHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSLicensingをいじるとなんとかなったりする。
・HardwareID,Parameters,Storeをリネームするなどしてバックアップ。特にHardwareID\ClientHWIDがなくなると何とかして書き戻すまでリモートデスクトップ接続がまったく使えなくなるため注意。
・HardwareID\ClientHWIDに元の値の末尾を適当にちょこっとかえた値を設定すると繋がるようになる。
<div style="padding-left:10%;"> <textarea style="width:80%"></textarea> </div>
というHTMLがあると、以下のように表示されます。
IE6で見てる人は上のテキストエリアをクリックして何か書き込んでみてください。突然テキストエリアが右ににょきっと延びるはずです。と、まぁこういう困ったバグがあるのですが、これは親要素にwidthを指定してやることで解消されます。
<div style="padding-left:10%;width:100%"> <textarea style="width:80%"></textarea> </div>
Function.prototype.bind = function(object) {
//関数のthisを取得
var __method = this;
//objectを退避
var __object = object;
//引数の配列を用意(ただし一番初めのthisをshiftして取り除く)
var __arguments = arguments;
for( var index = 0; index < __arguments.length-1; ++index )
__arguments[index] = __arguments[index+1];
__arguments.length = __arguments.length-1;
//thisにbindした関数を実行する無名関数を返す。
return function(){ __method.apply(__object, __arguments); }
}
function Obj1() {
this.counter = 0;
this.caller(2);
}
Obj1.prototype.caller = function( step ) {
this.counter += step
alert( this.counter );
setTimeout( this.caller.bind(this, step), 100 )
}
obj1 = new Obj1();こんな感じ。prototype.jsを使ってるならFunction.prototype.bindを使ったほうが早し。
Apatch2.0で遭遇したエラー。
具体的な内容については下とかが詳しいが、
http://sagittarius.dip.jp/~toshi/premature.html
http://it-revolution.seesaa.net/article/13687310.html
いろいろ試していても直る気配がない。
一か八かパーミッションを端から試していったところ、755から744に変えたら動作した…。謎。
bjam -sTOOLS=vc-8_0としてlibboost_regex_*.libとかを作って、そこにライブラリパスの設定が必要。
helpstring("IAxWinAmbientDispatchEx2 Interface"),
interface IAxWinAmbientDispatchEx2 : IDispatch
CComQIPtr<IAxWinAmbientDispatchEx2> m_spAxAmbient;
//#include <atlimpl.cpp>MtlProfile.h
//using WTL::wtlTraceFlags;DeskBandHost.h
//AtlDumpIID(riid, _T(""), S_OK);REG_EXPRESSION expression = REG_EXPRESSION( static_cast<LPCTSTR>(strPattern) );
inline void MtlShowInternetOptions()ExplorerTreeViewCtrl.h
const int s_unknownOffset = 12;
static void _TreeItemMask(TVITEM& item, ULONG dwAttributes)
typedef typename tyRtlList::iterator tyRtlListItr;
MtlDragDrop.hATL::InlineIsEqualGUID(riid, IID_IDocHostUIHandlerDispatch))
ATL::InlineIsEqualGUID(riid, IID_IDropTarget)
#define CopyCursor(pcur) ((HCURSOR)CopyIcon((HICON)(pcur)))
hCursor = CopyCursor(LoadCursor(hInstHelp, MAKEINTRESOURCE(106)));
/*ATLTRY(*/CChildFrame* pChild = NEW CChildFrame(tabMDI, adBar, bNewWindow2, dwDLFlags)/*)*/;
g_hDllInst =_Module.m_hInstResource = g_hModuleInst;
g_hDllInst = _Module.m_hInstResource;
const UINT uDiff = (UINT)sqrt(pow(static_cast<double>(ptUp.x - ptDown.x), 2) + pow(static_cast<double>(ptUp.y - ptDown.y), 2));
nDiff = sqrt(pow(static_cast<double>(ptBefor.x - ptUp.x), 2) + pow(static_cast<double>(ptBefor.y - ptUp.y), 2));
MtlRefreshBandIdealSize(CReBarCtrl(GetParent()), m_hWnd);
MTL::CLogFont lf;
GUID guid;
hRes = _Module.Init(NULL, hInstance, &guid);
template<class T, WORD w_tDlgTemplateID> class ATL_NO_VTABLE CTreeOptionPageImpl : public CDialogImpl<CTreeOptionPageImpl> , public CWinDataExchange<CTreeOptionPageImpl>, public CMessageFilterを
template<class T, WORD w_tDlgTemplateID> class ATL_NO_VTABLE CTreeOptionPageImpl : public CDialogImpl<CTreeOptionPageImpl<T, w_tDlgTemplateID> > , public CWinDataExchange<CTreeOptionPageImpl<T, w_tDlgTemplateID> >, public CMessageFilterとする。
http://mtamaki.cocolog-nifty.com/blog/2006/03/post_d1da.html
のおまけ。
http://www.aurora.dti.ne.jp/~m-tamaki/FullControler_060320.zip指定したフォルダ以下のすべてのファイルとフォルダにFullControlerを起動したユーザーとAdministratorsのフルコントロールを付加します。
FullControler.exe -user "username"
として起動するとusernameのフルコントロールを付加することも出来ます。
http://www.aurora.dti.ne.jp/~m-tamaki/AdministrateDeleter_060320.zip
Windowsのセキュリティの勉強用に作ったツール。
指定のフォルダ以下のすべてのファイルとフォルダを削除します。
このとき、アクセス権や所有権がなくて削除に失敗しても所有権を分捕ってアクセス権を設定して削除しようとします。
というソフトなので、環境移行時なんかに出来てしまったどうしても消せないファイルやフォルダの削除に使えるかもしれません。
ただし、使用する際には非常にご注意ください。通常削除できないファイルもとてもがんばって一生懸命削除してしまうので本当に注意して使ってください。
SVNのレポジトリにスペルは一緒だけど大文字小文字が違うファイルができてしまったとき、Windowsではチェックアウトやアップデートに失敗する。
こういうときはレポジトリブラウザで同名のファイルをリネームしたり、削除すればOK
| 固定リンク | コメント (0) | トラックバック (0)
無線LANを使うのに丸2日かかりました。
とりあえず以下にやり方を記録。
これで起動時に自動的につながるようになるはず。
以下調べてるときのメモ。
| 固定リンク | コメント (0) | トラックバック (0)
Windowsで他のPCからパスワードの入力なしにフォルダを共有したいときについてのメモ。
Windowsは他のPCの共有フォルダを見ようとするとき、まず自動でGuestアカウントでそのPCにログインしようとする。共有フォルダにパスワードなしでアクセスできないときはこのプロセスに失敗していることが多い。
自動でGuestアカウントにログインできるためには以下の3つの条件が必要。
たまにしか再現しない、どうやっても再現したりしなかったりする、といった場合はメモリの初期化忘れを疑ってみよう。
これから起こるバグはかなり厄介。まず、OSが起動してから同じアプリケーションの二回目以降の起動では多くの場合同じメモリが使いまわされて、なおかつ前回のメモリ状態が残っていることが多い。
このために二回目以降は前回終了時の値が入ったままになり、そういった値は意外とアルゴリズムにとって初期値として致命的でないのでぱっと見動いてしまう。
しかし、リリースした後にほかのPCとかに入れてみると最初の挙動が変、とかそういうことになる。
ていうか、なったorz
本当に入れてみただけど、とりあえずその記録。
Debian.jpからリンクをたどって流れに流れ
http://ftp.egr.msu.edu/debian/dists/sarge/main/installer-i386/current//images/floppy/
から
の4つの.imgファイルをダウンロード。さらに
http://ftp.egr.msu.edu/debian/tools/rwwrtwin.zip
もダウンロード。
んで、FDDを4枚フォーマットしてrwwrtwin.exeで4つのimgをFDDに書き込む。
んで、bootをマシンのFDDに入れて再起動。
するもエラーで止まりまくる。
どうもFDが古かったみたいでうまく書き込めなかった。5枚くらい失敗したのでこれからやる人は新しいFDを買ってきたほうがいいかも。
その後はダイアログに従って適当に進めて言ったらとりあえず動く環境が完成。
終了はアクション→ログアウトでシャットダウンを選んで終了。
PSDKを使ってMIDLをコンパイルするプロジェクトのソースコードをほかの場所に持っていってもう一度コンパイルしようとするとき、たいていredefinitionエラーになる。
これは新しい環境でPSDKのincludeフォルダのパスをプロジェクトかVCに設定していないため。
ただしPSDKのincludeのパスを設定してもリビルドするまできちんとコンパイルできない。
| 固定リンク | コメント (0) | トラックバック (0)
管理者権限を持たないで開発する方法 - Visual Studio
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/tchDevelopingSoftwareInVisualStudioNETWithNon-AdministrativePrivileges.asp
社本@ワック Blog より。
社本さんのBlogのタイトルからは管理者権限を持たないで開発する方法のKBって読み取れるけど、元のページを超すごいめっちゃ斜め読みした雰囲気から言うと、元のKBは「管理者権限で開発してても実際使うユーザーは管理者権限持ってなかったりするから、いざっていうときに動かなかったりセキュリティの面から言ってもよくないんだよー。というわけで開発者の皆さんには通常のユーザー権限で開発することをお勧めします。」って感じ(たぶん)。
実際、管理者権限を普段持たないのはお勧めです。共有マシンとか制限された環境で作業することが増えてきた人は多いんじゃないかな。
ちなみに具体的には以下のようにします。
とまあ、たぶんこの2つを準備すればOK。前述のKBにはもっとほかのことも書いてあるかも。(そこまでちゃんと読んでない。。。)
TortoiseSVN(というかTortoiseMerge)ではBOMなしのUTF-8のコードページをきちんと読み込んでくれない。と、主にXMLのDiffやMergeが文字化けする。が、WinMergeの最新版だと読むことができる。
落とすときには06/03/09時点では上から2つ目のWinMerge 2.5.3.2-jp-1以降を選ぶこと。
これをインストールした後でTortoiseSVNの設定を開き、External Programsを軒並みExternalにしてパスをWinMergeU.exeにする。
あと、WinMergeの設定を開き、編集→設定で.html,.rc,.xmlのコードページ情報を検出するとmlang.dllを使用してファイルのコードページを検出するを有効にすると読めるようになる。
| 固定リンク | コメント (0) | トラックバック (0)
だということを今日はじめて知った。なんかショック。今まで書きまくってたよorz
http://www.yuhisa.com/cgi/htmllint/explain.html#bad-entity
http://www.bar.com/foo.cgi?a=b&c=d というURLは http://www.bar.com/foo.cgi?a=b&c=d と書かなきゃいけない、という話。
HTMLのタグの内容の部分は実体参照にしなきゃいけないのは知ってたけど属性値は例外だと勝手に思い込んでた。ぐー。
ちなみにIEとかは上のどっちでも解釈してくれちゃったりします。でもampってキーがあったら誤認識とかのきっかけになりそうだし。気をつけます。
cherrypyというPurePythonのHTTPDがある。残念ながらHTTP1.0しか扱えないのであまり早くないが、pythonでちょっとしたローカルサーバーを作るには非常に便利なモジュール。
そのcherrypy2.1.0であるポートを開こうとしたとき、そのポートがすでに使われていると当然ながら開けずにエラーになるのだが、そのときのブロック時間が超長い。この待ち時間はconfigではどうやら変更できなさそうだ。
が、_cpserver.pyの342行目あたり、def wait_for_free_port(host, port):の for trial in xrange(50): の50を5とかにすると超早くなる。
成功するときはたいてい一発でつながるので5回も試行してだめならとっとと別のポートを開いた方がいいっす。たぶん。
| 固定リンク | コメント (0) | トラックバック (0)
昔のHPから今でも価値がありそうな情報だけど、ひとつのエントリにするほどのものじゃないのを片っ端からリストアップ。03年ごろの情報が多くて、たまに古いのだと95年とかだったりするので情報の信頼性は低いと見てください。ヒント程度に。
>セキュリティ保護のため、コンピュータにアクセスできるアクティブコンテンツは表示され >ないよう、Internet Explorerで制限されています。オプションを表示するには、ここを >クリックしてください。
(2)インターネットエクスプローラの「ツール」メニューから「インターネットオプション」 を選択します。 「詳細設定」のタブを選んで下記の2項目の所にチェックを入れて下さい。 [マイコンピュータでの、CDのアクティブコンテンツの実行を許可する] [マイコンピュータのファイルでのアクティブコンテンツの実行を許可する]
| 固定リンク | コメント (0) | トラックバック (0)
//////////////////////////////////////////////////////////////////////////////// LRESULT __stdcall FileDialog::OKWndProcHook(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { FileDialog* pThis = TB_ENFORCE( NullFail(), reinterpret_cast< FileDialog* >( GetLongPtr( hWnd, GWLP_USERDATA ) ) ); if( WM_LBUTTONUP == uMsg ) { //通常OKボタンを押したときフォルダだけが選択されていたならそのフォルダに移動する。 //ただしフォルダも選択するオプションが有効ならその操作をキャンセルして閉じる。 //基本的にはOkボタンが押されたら閉じるが、もしMustExistフラグが立っていたら作成をユーザーに問い合わせる必要がある。 //ただし作成を行うのはエディットボックスに何か値が入っていたら。値が入っていなければただOKボタンが押されたのを無視する。 //これらの操作は基本的にmPathsがemptyのときだけ。 HWND hParent = GetParent( hWnd ); if( pThis->mPaths.empty() ) { //MustExistで、現在選択されてるファイルが存在しない場合は警告を表示 if( pThis->mIsMustExist ) { TB_STRING file = CommDlgOpenSaveGetFilePath( hParent ); if( !IsExist( file ) ) { if( IDYES == MessageBox( hParent, (file + _T( "\nこのファイルは存在しません。\n\n作成しますか?" )).c_str(), GetTitle( hParent ).c_str(), MB_YESNO ) ) { CreateFile( file ); pThis->mPaths.push_back( file ); EndDialog( hParent, IDOK ); } } } } else EndDialog( GetParent( hWnd ), IDOK ); } return CallWindowProc( TB_ENFORCE( NullFail(), pThis->mOriginalProc ), hWnd, uMsg, wParam, lParam ); } //////////////////////////////////////////////////////////////////////////////// UINT __stdcall FileDialog::ShowDialogHook(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if( WM_NOTIFY == uMsg ) { UINT code = reinterpret_cast< NMHDR* >( lParam )->code; HWND hParent = GetParent( hWnd ); switch( code ) { case CDN_INITDONE: //センタリング Move( hParent, Centering( GetScreenRect(), GetWindowRect( hParent ) ) ); case CDN_SELCHANGE: case CDN_FOLDERCHANGE: { FileDialog* pThis = TB_ENFORCE( NullFail(), reinterpret_cast< FileDialog* >( reinterpret_cast< LPOFNOTIFY >( lParam )->lpOFN->lCustData ) ); if( !pThis->mIsFolderSelectable ) break; switch( code ) { case CDN_INITDONE: { //OKボタンのHWNDを取得 HWND hOK = GetChild( hParent, _T( "開く(&O)" ) ); //OkボタンのユーザーデータにFileDialogのthisを仕込む。 SetLongPtr( hOK, GWLP_USERDATA, reinterpret_cast< LONG_PTR >( pThis ) ); //OKボタンをサブクラス化 pThis->mOriginalProc = SubClass( hOK, OKWndProcHook ); } break; case CDN_SELCHANGE: { //リストビューで選択されている項目のタイトルを取得して、現在選択しているフォルダのパスを先頭にくっつけてmPathsに保存 pThis->mPaths = ( CommDlgOpenSaveGetFolderPath( hParent ) + _T( "\\" ) ) + GetSelectedItemTitle( TB_ENFORCE( NullFail(), GetChild( hParent, _T( "FolderView" ) ) ) ); } break; case CDN_FOLDERCHANGE: { //フォルダが変更された。 //何も選択されていないはずなので選択をクリア pThis->mPaths.clear(); } break; } } return TRUE; } } return FALSE; } ///////////////////////////////////////// bool FileDialog::ShowDialog( tDialogFunction DialogFunction ) { //絶対パスに変換して書き換え可能なバッファに格納(ofn.lpstrFileがconstじゃないので。) TB_STRING temp = GetAbsolutePath( mRelativeBase, GetPrivateProfileString( mIniPath, mSection, mKey, mInitialPath ) ); std::vector< _TCHAR > result( temp.c_str(), temp.c_str() + temp.size() + 1 ); result.resize( MAX_PATH*2, '\0' ); //デフォルト拡張子を設定する。 if( mDefaultExtension.empty() ) { //まだ設定されていない //ファイルタイプが設定されていればそれの先頭の拡張子を使う。 if( !mFileTypes.empty() ) mDefaultExtension = mFileTypes[0].second; else if( '\0' != result[0]) { //ファイルタイプはないけど、初期ファイル名があるならその拡張子を使う。 TB_STRING extension = &result[0]; TB_STRING::size_type position = extension.rfind( _T( "." ) ); extension = extension.substr( TB_STRING::npos == position ? 0 : position ); } } //ファイルタイプを作成する。 std::vector< _TCHAR > filters; { //全てのファイル(*)を追加。 AddFileType( _T( "全てのファイル" ), _T( "*" ) ); //二重NULL終端文字列群を作成 FileTypes::iterator endIt = mFileTypes.end(); for( FileTypes::iterator it = mFileTypes.begin(); it != endIt; ++it ) { filters.insert( filters.end(), it->first.c_str(), it->first.c_str() + it->first.length() ); filters.push_back( '(' ); filters.insert( filters.end(), it->second.c_str(), it->second.c_str() + it->second.length() ); filters.push_back( ')' ); filters.push_back( '\0' ); filters.insert( filters.end(), it->second.c_str(), it->second.c_str() + it->second.length() + 1 ); } filters.push_back( '\0' ); } OPENFILENAME ofn = { sizeof( OPENFILENAME ) }; ofn.Flags = OFN_EXPLORER | OFN_ENABLEHOOK; if( mIsMultiSelect ) ofn.Flags |= OFN_ALLOWMULTISELECT; if( mIsMustExist ) ofn.Flags |= OFN_CREATEPROMPT; ofn.lpstrTitle = mTitle.empty() ? NULL : mTitle.c_str(); ofn.lpstrFile = &result[0]; ofn.nMaxFile = TB_NUMERIC_CAST< DWORD >( result.size() ); ofn.lpstrFilter = &filters[0]; ofn.lpstrDefExt = mDefaultExtension.c_str(); ofn.hwndOwner = mhWnd; ofn.lpfnHook = ShowDialogHook; ofn.lCustData = reinterpret_cast< LPARAM >( this ); if( !DialogFunction(&ofn) ) { TB_ENFORCE( CommonDialog(), CommDlgExtendedError() ); mPaths.clear(); return false; } //FolderSelectableでない場合はresultからファイルを抽出する。 if( !mIsFolderSelectable && mIsMultiSelect ) { std::vector< _TCHAR > path; _TCHAR* pIndex2 = &result[0] + lstrlen( &result[0] ); for( _TCHAR* pIndex = pIndex2+1; pIndex[0] != '\0'; pIndex += lstrlen( pIndex )+1 ) { //まずカレントディレクトリをコピー path.assign( &result[0], pIndex2 ); path.push_back( '\\' ); path.insert( path.end(), pIndex, pIndex + lstrlen( pIndex ) + 1 ); mPaths.push_back( &path[0] ); } } //MustExistフラグが寝てて、フォルダを切り替えた直後にOkを押した場合、mPathが空。 //resultの値を使う。 if( mPaths.empty() ) mPaths.push_back( &result[0] ); //Iniに保存 WritePrivateProfileString( mIniPath, mSection, mKey, mIsRelative ? GetRelativePath( mRelativeBase, mPaths[0] ) : mPaths[0] ); return true; } ////////////////////////////////////////////////////////////////////////////////
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
//////////////////////////////////////////////////////////////////////////////// //stl #include <string> //windows #include <windows.h> #include <Shlobj.h> #pragma comment(lib, "Ole32.lib") //////////////////////////////////////////////////////////////////////////////// #if !defined( TBENFORCEH ) #define TB_ENFORCE( enforcer, statement ) statement #pragma warning( disable :4552 ) //warning C4552: '!' : 演算子にプログラム上の作用がありません。作用を持つ演算子を使用してください #endif //#if !defined( TBENFORCEH ) //////////////////////////////////////////////////////////////////////////////// class System { public: virtual ~System() throw(){} static void Run( const std::string& path ); }; //////////////////////////////////////////////////////////////////////////////// void System::Run( const std::string& path ) { //COMを初期化 TB_ENFORCE( NotEqualFail( S_OK ), CoInitialize( NULL ) ); //デスクトップフォルダを取得 IShellFolder* pDesktopFolder; TB_ENFORCE( NotEqualFail( S_OK ), ::SHGetDesktopFolder( &pDesktopFolder ) ); //引数のパスへのフルパスを含むITEMIDLISTを作成 LPITEMIDLIST pFullPathIDList; { //まず引数をユニコードに変換 OLECHAR convertedPath[MAX_PATH*2+1]; TB_ENFORCE( API(), ::MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, path.c_str(), -1, convertedPath, MAX_PATH*2 ) ); //ITEMIDLISTを取得 ULONG chEaten, dwAttributes; TB_ENFORCE( NotEqualFail( S_OK ), pDesktopFolder->ParseDisplayName( NULL, NULL, convertedPath, &chEaten, &pFullPathIDList, &dwAttributes ) ); } //引数のパスの親フォルダのIShellFolderを取得。 IShellFolder* pCurrent = pDesktopFolder; { //IMallocを取得しておく。 IMalloc* pMalloc; ::SHGetMalloc( &pMalloc ); //IShellFolderをトラバース do { //フルパスを示すITEMIDLISTから今見ているフォルダのITEMIDLISTをコピー LPITEMIDLIST pCurrentIDList; { //コピー元のアイテムのサイズを取得 int srcSize = pFullPathIDList->mkid.cb; //コピー先のサイズはUSHORTのサイズを足したもの int dstSize = srcSize + sizeof(USHORT); //新しいアイテム用メモリを確保 pCurrentIDList = reinterpret_cast< LPITEMIDLIST >( TB_ENFORCE( NullFail(), pMalloc->Alloc( dstSize ) ) ); //内容をコピー memcpy( pCurrentIDList, pFullPathIDList, srcSize ); //余りは0で埋める。 memset( reinterpret_cast<LPBYTE>(pCurrentIDList) + srcSize, 0, dstSize - srcSize ); } //今見てるフォルダのITEMIDLISTからIShellFolderを取得 IShellFolder* pTemp; TB_ENFORCE( NotEqualFail( S_OK ), pCurrent->BindToObject( pCurrentIDList, NULL, IID_IShellFolder, reinterpret_cast< void**>( &pTemp ) ) ); //取得できたので前のIShellFolderは解放 pCurrent->Release(); //pCurrentを置き換える。 pCurrent = pTemp; //ついでにITEMIDLISTもいらないので解放 pMalloc->Free( pCurrentIDList ); //ItemIDListを次に進める。 pFullPathIDList = reinterpret_cast<LPITEMIDLIST>( ( reinterpret_cast<LPBYTE>( pFullPathIDList ) ) + pFullPathIDList->mkid.cb ); } while( reinterpret_cast<LPITEMIDLIST>( ( reinterpret_cast<LPBYTE>( pFullPathIDList ) ) + pFullPathIDList->mkid.cb )->mkid.cb != 0 ); //↑pFullPathIDListの次がsize==0ならループを終わる。 //IMallocを解放 pMalloc->Release(); } //pCurrentがpathの指すファイルの親フォルダ。 //pFullPathIDListは今ファイル名を指す。 //以上の情報からそのファイルの右クリックメニューを取得して既定のコマンドを実行 //まずIContextMenuを取得。 IContextMenu* pContextMenu; TB_ENFORCE( NotEqualFail( S_OK ), pCurrent->GetUIObjectOf( NULL, 1, ( LPCITEMIDLIST* )(&pFullPathIDList), IID_IContextMenu, 0, reinterpret_cast< void ** >( &pContextMenu ) ) ); {//コマンドを実行 //IContextMenu::InvokeCommandの引数用構造体を用意 CMINVOKECOMMANDINFO invokeInfo = { sizeof( invokeInfo ) }; //lpVerbメンバにメニューの識別子を設定 HMENU hMenu = TB_ENFORCE( API< HMENU >( NULL ), ::CreatePopupMenu() ); TB_ENFORCE( TrueFail(), FAILED( pContextMenu->QueryContextMenu( hMenu, 0, 1, 0xffff, CMF_EXPLORE ) ) ); invokeInfo.lpVerb = MAKEINTRESOURCE( TB_ENFORCE( EqualFail( -1 ), GetMenuItemID( hMenu, TB_ENFORCE( API(-1), GetMenuDefaultItem( hMenu, TRUE, NULL ) ) ) )-1 ); invokeInfo.nShow = SW_SHOWNORMAL;
//実行 HRESULT result = pContextMenu->InvokeCommand( &invokeInfo ); //「0x800704c7 この操作はユーザーによって取り消されました。」の場合はエラーとしない。 if( 0x800704c7 != result && S_OK != result ) TB_ENFORCE( FalseFail(), !"pContextMenu->InvokeCommand( &invokeInfo )" ); } //COMを解放 CoUninitialize(); } ////////////////////////////////////////////////////////////////////////////////
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
C:\Program Files\Microsoft DirectX 9.0 SDK (April 2005)\Extras\DirectShow\Samples\C++\DirectShow\BaseClasses\combase.h
にある。
#define AM_NOVTABLE #include <wxdebug.h> #include <Combase.h>
こうすると通る。
| 固定リンク | コメント (0) | トラックバック (0)
DirectX9のSDKはVC用に作られていて、そのままではBCBでリンクが通らない。
以前のDXはcoff2omf.exeというツールでBCB用に変換できたが、DX9のは無効なファイルが出来上がってしまって使えない。
DLLからlibを作る方法もあるが、libしかないファイルもあり、やはりリンクができない場合がある。
が、BCB用のlibを提供しているところがあった。
(Ref: http://clootie.narod.ru/cbuilder/index.html )
libsやdllsを置いてるページがくそ重なので直りん
http://clootie.narod.ru/delphi/DX92/Clootie_DX92_dlls.zip
http://clootie.narod.ru/delphi/DX92/CBuilder_DX92_libs.zip
中ほどの"DirectX libraries for C++Builder"の"CBuilder_DX92_libs.zip"がlibファイル群となる。
これをダウンロードして展開し、BCBのプロジェクトオプションのディレクトリ設定のライブラリファイルのところに展開先のパスを指定してやればよい。
これでリンクは通るが、実行時にDLLがないといってエラーになる。これは先のページの"Clootie_DX92_dlls.zip"を落としてきて展開し、中の2つのDLLをwindows\system32のようなパスの通ったディレクトリに放り込めば解決される。
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
class TForm1 : public TForm { // : protected: void __fastcall OnDialogKey(Messages::TWMKey &Message) { if( Message.CharCode != VK_LEFT ) TForm::Dispatch( &Message ); } BEGIN_MESSAGE_MAP MESSAGE_HANDLER( CM_DIALOGKEY, Messages::TWMKey, OnDialogKey ); END_MESSAGE_MAP(TForm) };上のような感じです。他の無効にしたいキーも同じく記述します。
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
Uint Binarize::GetThresholdByOptimizedOtsu( const std::vector< Uint8 >& picture ) { //画像の先頭ポインタを取得 const Uint8 * pPicture = &picture[0]; //ヒストグラム用バッファを用意 std::vector<double> histogram(256, 0); //ヒストグラムを作成 TB_LOOP_1( picture.size() ) ++histogram[*pPicture++]; //ヒストグラムの各要素を画像サイズで除算して正規化ヒストグラム(濃度の確率分布)を作成 std::transform(histogram.begin(), histogram.end(), histogram.begin(), std::bind2nd(std::divides<double>(), picture.size())); //濃度分布の0次モーメント用のバッファを用意 std::vector<double> partial0thMoment(256); //全体の部分和を計算({1,2,3,4}→{1,3,6,10}) std::partial_sum(histogram.begin(), histogram.end(), partial0thMoment.begin()); //濃度分布の1次モーメント用のバッファを用意 std::vector<double> partial1stMoment(256); //正規化ヒストグラムに輝度をかけたものをバッファにコピー TB_LOOP_1( 256 ) partial1stMoment[index] = index*histogram[index]; //それの部分和を計算 std::partial_sum(partial1stMoment.begin(), partial1stMoment.end(), partial1stMoment.begin()); //全平均輝度レベル double total1stMoment = partial1stMoment.back(); //クラス内分散 std::vector<double> interClassVariance(256); TB_LOOP_1( 256 ) { //クラス内分散を求める。(全平均輝度レベル×輝度i間での濃度分布の0次モーメント-輝度i間での濃度分布の1次モーメント)^2を double temp = total1stMoment * partial0thMoment[index] - partial1stMoment[index]; //輝度i間での濃度分布の0次モーメント×(1-輝度i間での濃度分布の0次モーメント)で割る。 interClassVariance[index] = temp*temp / (partial0thMoment[index]*(1-partial0thMoment[index])); //この辺は基本的なアルゴリズムを数学的にかなり畳み込んでる。 //おそらく原本は"Feature Extraction & Image Processing" "Mark S. Nixon, Alberto Aguado" ISBN: 0750650788 の p77~。 //訳だと"はじめての画像処理技術 ビギナーズブックス" "岡崎 彰夫" ISBN: 4769351224 の p78~。 } //もともとはクラス間分散/クラス内分散でもっとも大きな値をとるような閾値が最適閾値なのだけど、 //数学的にクラス間分散/クラス内分散が最大となる閾値とクラス内分散が最も大きくなる閾値が等価。よってクラス内分散の最大値となる閾値を求める。 return std::max_element(interClassVariance.begin(), interClassVariance.end()) - interClassVariance.begin(); }
| 固定リンク | コメント (0) | トラックバック (0)
子コントロール同士で重なりあっていて、それぞれWM_PAINTで描画処理している場合、下のコントロールがWM_PAINTを処理してしまって上のコントロールにWM_PAINTが行かないときがある。
BeginPaint中はValidateRectは使えないので、下のコントロールのWM_PAINTの処理が終わり次第上のコントロールにInvalidateRectしてやればよい。
| 固定リンク | コメント (0) | トラックバック (0)
void Process::SetFullScreenMode() { //プロセス起動直後にAttachConsoleしようとするとたいていうまく行かない。 Sleep(1000); if( AttachConsole( TB_ENFORCE( API(), GetProcessId( mProcess ) ) ) ) { TB_ENFORCE_TO_THROW { DllProc< BOOL (WINAPI*) (HANDLE,DWORD,COORD*) > SetConsoleDisplayMode( FilePath( FolderPath::GetWindowsFolder(), "kernel32.dll" ), "SetConsoleDisplayMode" ); COORD coord; const int CONSOLE_FULLSCREEN_MODE = 1; TB_ENFORCE( API(), SetConsoleDisplayMode()( TB_ENFORCE( API(INVALID_HANDLE_VALUE), GetStdHandle( STD_OUTPUT_HANDLE ) ), CONSOLE_FULLSCREEN_MODE, &coord ) ); } TB_ENFORCE_CATCH { //まずコンソールウインドウのハンドルを何とかしてとってくる。 //そのためにウインドウタイトルをユニークなIDで置き換える。 //同じアルゴリズムを使うプログラムと競合する可能性が(0%に近いけど)あるのでIdはGUIDを使う。 std::string guid = "{6A47F119-E665-4533-99CB-BDF3ABE2B1D0}"; //タイトルをバックアップ StringReceiver title; TB_ENFORCE( API(), GetConsoleTitle(title.Lock( 1024 ), 1023 ) ); //置き換える。 TB_ENFORCE( API(), SetConsoleTitle(guid.c_str()) ); //別プロセスなのでウインドウタイトルをセットするためのコンテキストスイッチを起こして待つ。 Sleep(50); //ウインドウタイトルを検索してハンドルを得る。 //win9x系のコンソールのウインドウクラスはtty HWND hConWnd = TB_ENFORCE( API<HWND>(NULL), FindWindow("tty", guid.c_str()) ); //タイトルを元に戻す TB_ENFORCE( API(), SetConsoleTitle(title.UnLock().c_str()) ); // pause before changing to fullscreen //Sleep(450); //コンソールウインドウにWM_COMMAND,57359,0を送ると全画面化する。 SendMessage( hConWnd, WM_COMMAND, 57359, 0 ); } TB_ENFORCE( API(), FreeConsole() ); } }
while( !AttachConsole( mProcessID ) )
Sleep(500);みたいなコードを書いても一度失敗したらなぜか二度と成功しません(アタッチしたい相手先のコンソールは元気に動いてます)。------ ------ ------ ------ ------ ------ ------ ------ |....| |....| |....| |....| |....| |....| |....| |....| |....| |^...| |^...| |^...| |^O..| |^O..| |^O..| |^@..| |.._.| |.^O.| |P^O.| |P^O.| |P^@.| |P^_.| |P^_.| |O^_.| |....| |.P@.| |..@.| |...@| |....| |.@..| |.^@.| |P^..| -.---- -.---- -.---- -.---- -.---- -.---- -.---- -.----で、僧侶が梃子でも動こうとしなくなるのです。というかプレイヤーが寺院に入るとほとんど祭壇の周り1マスから離れようとしなくなります。
------ ------ |...@| |....| |P...| |.```| |.._.| |.P@`| |....| |.```| -.---- -.---- @:プレイヤー P:僧侶 _:祭壇このとき僧侶は自分の隣のますにいます。表示されていませんがこの僧侶の上にも岩があります。
------ ------ ------ |....| |....| |.@..| |.*``| |.@``| |.*``| |.P@`| |.P``| |.P``| |.```| |.```| |.```| -.---- -.---- -.----んでしばらく足踏みをすると僧侶が動きます。祭壇の周り1マスのうち動けるのはさっき砕いたマスだけなのでそこに移動するでしょう。
------ |.@..| |.P``| |.```| |.```| -.----一見このまま僧侶はどこにも行かず固まるのかと思いきや、しばらく足踏みしてると別のマスに移動を始めます。
------ |.@..| |.*``| |P```| |.```| -.----こうなったらしめたもの、砕いた岩のますのところに落とし穴を掘って祭壇のまわり一マスに僧侶をいけなくします。
------ ------ ------ ------ ------ ------ ------ -.---- -@---- -.---- -.---- |....| |....| |....| |.P..| |.P`.| |P`@.| |`@..| |`@..| |`...| |....| |....| |.@``| |@^``| |.^``| |.^``| |.^`@| |.^`.| |P^`.| |P^`.| |P^`.| |@^`.| |.^`@| |P```| |P```| |.```. |.```@ |.```. |.```. |.```. |.```. |.```. |````. |``*`. |.```| |.```| |P```|@ |.```| |.```| |.```| |.```| |.```| |.```| |P```| |P```| -.---- -.---- -.---- -.---- -.---- -.---- -.---- -.---- -.---- -.---- -.----と、まぁこんな感じで乗っ取り完了です。後は祭壇に死体をささげて転換して、レベル低ければ幽霊レベルアップ、その後は僧侶に蟻を召還してもらってレベル上げ&アーティファクトゲット!詳しくは前述のページを参照のこと。
| 固定リンク | コメント (0) | トラックバック (0)
いいところ
画面がSXGA+(1400*1050)なので広い。
ノートパソコンのスピーカーにしてはいい音がする。
悪いところ。
もろい。ちょっと本体を捻ると結構な確率でハードエラーで青画面になったりする。
でかい。とことんでかい。
CD-ROMドライブが打たれ弱い。(どのノートでもそうだけど…。)
4年くらい使うとCPUファンのグリスが切れます。油とかさすと吉。
| 固定リンク | コメント (0) | トラックバック (0)
英単語を調べるのに便利。
Sleipnirの検索に登録するとよいかと。
http://wwwd.nova.co.jp/webdic/webdicc.cgi?&lang=X&dic=BASE&dic=MATH&dic=MEDI&dic=AERO&dic=BUSI&dic=COMP&dic=META&dic=ARCH&dic=OCEA&dic=TRAD&dic=ELEC &dic=CHEM&dic=PLAN&dic=DEFE&dic=FINA&dic=MECH&dic=BIO&dic=ENER&dic=ECOL&dic=LAW&dic=ENTE&magazine=yes
うえのURLにさらに
&adrs=emailアドレス
&word=検索文字列
を追加して使います。
| 固定リンク | コメント (0) | トラックバック (0)
int __stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) { IMalloc* pMalloc; TB_ENFORCE( NotEqualFail( S_OK ), CoGetMalloc( 1, &pMalloc ) ); LPITEMIDLIST pIdList; TB_ENFORCE( NotEqualFail( S_OK ), SHGetFolderLocation( NULL, CSIDL_DESKTOP, NULL, NULL, &pIdList ) ); IShellFolder* pDesktop; TB_ENFORCE( NotEqualFail( NOERROR ), SHGetDesktopFolder( &pDesktop ) ); // IContextMenuを取得します。 // m_pDFolderはデスクトップフォルダを示すIShellFolderです。 IContextMenu* pContextMenu; TB_ENFORCE( NotEqualFail( S_OK ), pDesktop->GetUIObjectOf( NULL, 1, (LPCITEMIDLIST*)(&pIdList), IID_IContextMenu, 0, reinterpret_cast< void ** >( &pContextMenu ) ) ); HMENU hMenu = TB_ENFORCE( API< HMENU >( NULL ), ::CreatePopupMenu() ); // メニューを取得します。 HRESULT re = pContextMenu->QueryContextMenu( hMenu, 0, 1, 0xffff, CMF_NORMAL ); Uint itemIndex = UINT_MAX; // TB_LOOP_1( GetMenuItemCount( hMenu ) ) { StringReceiver receiver; if( 0 != GetMenuString( hMenu, index, receiver.Lock( 255 ), 254, MF_BYPOSITION ) ) { //文字列が取得できた。 if( std::string::npos != receiver.UnLock().find("元に戻す") ) { itemIndex = index; break; } } } if( UINT_MAX == itemIndex ) { //「元に戻す」がない==削除や移動をしていなくて元に戻すファイルがない。 return 0L; } // コマンドを実行します。 CMINVOKECOMMANDINFO invokeInfo = { sizeof( CMINVOKECOMMANDINFO ) }; invokeInfo.fMask = 0; invokeInfo.hwnd = NULL; invokeInfo.lpVerb = MAKEINTRESOURCE( itemIndex );//MAKEINTRESOURCE( iCommand - 1 ); invokeInfo.lpParameters = NULL; invokeInfo.lpDirectory = NULL; invokeInfo.nShow = SW_SHOWNORMAL; invokeInfo.dwHotKey = 0; invokeInfo.hIcon = NULL; TB_ENFORCE( NotEqualFail( NOERROR ), pContextMenu->InvokeCommand( &invokeInfo ) ); window.Wait(); pContextMenu->Release(); pDesktop->Release(); pMalloc->Free( pIdList ); pMalloc->Release(); return 0L; }
エクスプローラー(&X)とかは取れるんだけどなぁ。
フォルダの拡張メニューはIShellFolderからGetUIObjectOfしたのではだめなのかもしれない。
上の記事の後に前進があったのでメモ
・CoInitializeとCoUninitializeを忘れてた。追加したら突如としてQueryContextMenuが以前より多い数のメニューを登録してきた。
謎。エラーになってるなら最初からエラー終了してほしい。
・フォルダのコンテキストメニューは無事取得成功。
したのはいいんだけど冷静になって考えると「元に戻す」があるのはフォルダの右クリックメニューではなくて、エクスプローラーの右ペインの何も無いところを右クリックしたときに出てくるメニュー。
これをとるためにIShellViewをとって、それのGetItemObjectを使った。
無事コンテキストメニューが取れた…のだが。
ない。狙ったように元に戻すの項目だけメニューに追加されてこない。
QueryContextMenuのパラメーターをいろいろといじるものの二進も三進も行かず。
IContextMenuでInvokeCommandすればいいなんて言い出したのは誰なんだ…。教えてほしい(^^;
とりあえずいったんあきらめた次第。
・IShellViewのメソッドをにらむにTranslateAcceleratorというのがある。これでCTRL+Zを送ってやろうかと思ったものの失敗。
MSG構造体を偽造するのは難しい。
int __stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) { CoInitialize( NULL ); IMalloc* pMalloc; TB_ENFORCE( NotEqualFail( S_OK ), CoGetMalloc( 1, &pMalloc ) ); LPITEMIDLIST pIdList; TB_ENFORCE( NotEqualFail( S_OK ), SHGetFolderLocation( NULL, CSIDL_DESKTOPDIRECTORY, NULL, NULL, &pIdList ) ); IShellFolder* pDesktop; TB_ENFORCE( NotEqualFail( NOERROR ), SHGetDesktopFolder( &pDesktop ) ); // IContextMenuを取得します。 IContextMenu* pContextMenu; IShellView* pView; TB_ENFORCE( NotEqualFail( S_OK ), pDesktop->CreateViewObject( NULL, IID_IShellView, reinterpret_cast< void ** >( &pView ) ) ); TB_ENFORCE( NotEqualFail( S_OK ), pView->GetItemObject( SVGIO_BACKGROUND, IID_IContextMenu, reinterpret_cast< void ** >( &pContextMenu ) ) ); // IContextMenu2へQueryInterface IContextMenu3* pContextMenu2; TB_ENFORCE( NotEqualFail( S_OK ), pContextMenu->QueryInterface( IID_IContextMenu3, reinterpret_cast< void ** >( &pContextMenu2 ) ) ); pContextMenu->Release(); HMENU hMenu = TB_ENFORCE( API< HMENU >( NULL ), ::CreatePopupMenu() ); // メニューを取得します。 HRESULT re = pContextMenu2->QueryContextMenu( hMenu, 0, 1, 0xffff, CMF_NODEFAULT ); Uint itemIndex = UINT_MAX; // TB_LOOP_1( GetMenuItemCount( hMenu ) ) { StringReceiver receiver; if( 0 != GetMenuString( hMenu, index, receiver.Lock( 255 ), 254, MF_BYPOSITION ) ) { //文字列が取得できた。 if( std::string::npos != receiver.UnLock().find("元に戻す") ) { itemIndex = index; break; } } } if( UINT_MAX == itemIndex ) { //「元に戻す」がない==削除や移動をしていなくて元に戻すファイルがない。 return 0L; } // コマンドを実行します。 CMINVOKECOMMANDINFO invokeInfo = { sizeof( CMINVOKECOMMANDINFO ) }; invokeInfo.fMask = 0; invokeInfo.hwnd = NULL; invokeInfo.lpVerb = MAKEINTRESOURCE( 7 );//itemIndex );//MAKEINTRESOURCE( iCommand - 1 ); invokeInfo.lpParameters = NULL; invokeInfo.lpDirectory = NULL; invokeInfo.nShow = SW_SHOWNORMAL; invokeInfo.dwHotKey = 0; invokeInfo.hIcon = NULL; TB_ENFORCE( NotEqualFail( NOERROR ), pContextMenu2->InvokeCommand( &invokeInfo ) ); pContextMenu2->Release(); pDesktop->Release(); pMalloc->Free( pIdList ); pMalloc->Release(); CoUninitialize(); return 0L; }
void FileSystem::Delete( const FilePath& path ) { CountDownTimer timer( 2000 ); while( timer() ) { //ゴミ箱に捨てる。 MultiString deletefilename; SHFILEOPSTRUCT shFileOp; shFileOp.hwnd = NULL; shFileOp.wFunc = FO_DELETE; shFileOp.pFrom = deletefilename.Make( vector< string >( 1, path() ) ); shFileOp.pTo = NULL; shFileOp.fFlags = FOF_ALLOWUNDO|FOF_NOCONFIRMATION|FOF_NOERRORUI; shFileOp.fAnyOperationsAborted = TRUE; if( SHFileOperation( &shFileOp ) == 0 ) return; //直前まで書き込みが行われていた場合など、エラーになるときがある。2秒まで再試行 } TB_ENFORCE( TrueFail(), ("FileSystem::Deleteに失敗:" + path()).c_str() ); }
まぁなんかこんな感じでSHFileOperationとFOF_ALLOWUNDOを使えばよい、というのはググればすぐに出てくるが、
肝心の「元に戻す」方法はほとんど資料がない。どうも話によるとごみ箱のコンテキストメニューをIFolderとIContextMenuを使って取得して
InvorkCommandで元に戻すを実行すればできる…らしいという話はある。
が、それも直前の操作を元に戻すものでしかない。ごみ箱に捨てた○○というファイルを元に戻すにはどうすればいいのか。
まずごみ箱はたいていC:\RECYCLERの下にある。ちなみにNT系を前提とする。しかも今回紹介する方法は2k以降でしか使えない。
C:\RECYCLERの下に、SID(セキュリティ識別子)と呼ばれるたいてい"S-1-5-21"といった文字列から始まるIDのフォルダが切られて、その中にごみ箱のファイルがある。ちなみに"Dc"+番号.拡張子という名前にリネームされている。
元のファイル名の情報はどこにあるのかというと、同じフォルダに"INFO2"という隠しファイルがあってそれがデータベースとなっている。
INFO2のフォーマットは
ヘッダ(謎)+(元のファイル名(ASCII)+NULL領域+Dcの後に来る番号(2バイト)+NULL領域+マルチバイトに変換されたファイル名+NULL領域)*
というもののようだ。元に戻した場合ファイル名のレコードは削除されないが、元のファイル名の最初の一文字が削られることで無効フラグとなっているらしい。
と、いうわけでかなり怪しげなものの、以下の方法でごみ箱から指定のファイルを元に戻すことができる。
・ごみ箱のINFO2ファイルを開く。
・元の位置のパスでINFO2を検索。
・見つかったらそのファイル名の後ろのNULL領域の次に来る2バイトがごみ箱内のファイルの番号。
・ごみ箱のファイルを元の位置に移動する。
INFO2ファイルのパスはIShellFolderを利用することで取得できる。
データベースファイルはどの環境でも"INFO2"というファイル名なのか、中のフォーマットは本当に正しいのか、ごみ箱のリネーム後のファイル名のヘッダはどこでも"Dc"なのか、などこの辺は確かな情報はない模様。
とりあえずうちで動作する「元に戻す」関数。
//! ごみ箱から指定のファイルを検索して復元 void FileSystem::Restore( const FilePath& restoreFile ) { //ごみ箱内のファイルをリストアップ std::vector< FilePath > paths; { //ShellAPIを使う。 IMalloc* pMalloc; TB_ENFORCE( NotEqualFail( S_OK ), CoGetMalloc( 1, &pMalloc ) ); LPITEMIDLIST pIdList; TB_ENFORCE( NotEqualFail( S_OK ), SHGetFolderLocation( NULL/*hwnd*/, CSIDL_BITBUCKET, NULL, NULL, &pIdList ) ); IShellFolder* pDesktop; TB_ENFORCE( NotEqualFail( NOERROR ), SHGetDesktopFolder( &pDesktop ) ); IShellFolder* pTrash; TB_ENFORCE( NotEqualFail( S_OK ), pDesktop->BindToObject( pIdList, NULL, IID_IShellFolder, reinterpret_cast< void ** >( &pTrash ) ) ); LPENUMIDLIST pEnumIDList; TB_ENFORCE( NotEqualFail( NOERROR ), pTrash->EnumObjects( NULL/*hwnd*/, SHCONTF_NONFOLDERS |SHCONTF_INCLUDEHIDDEN | SHCONTF_FOLDERS, &pEnumIDList ) ); LPITEMIDLIST pFileIDList; ULONG result; while( pEnumIDList->Next( 1, &pFileIDList, &result ) == NOERROR ) { // ファイルパスの取得。 STRRET stFileName; TB_ENFORCE( NotEqualFail( NOERROR ), pTrash->GetDisplayNameOf( pFileIDList, SHGDN_FORPARSING, &stFileName ) ); paths.push_back( String::ToAscii( stFileName.pOleStr ) ); pMalloc->Free( stFileName.pOleStr ); pMalloc->Free( pFileIDList ); } pMalloc->Free( pEnumIDList ); pTrash->Release(); pDesktop->Release(); pMalloc->Free( pIdList ); pMalloc->Release(); } //ごみ箱が空なら帰る。 TB_ENFORCE( TrueFail(), paths.empty() ); //ごみ箱の元のファイル名データベースを開く。 FilePath info2Path( paths[0].GetFolder(), "INFO2" ); TB_ENFORCE( FalseFail(), FileSystem::IsExist( info2Path ) ); //INFO2を開く。 BinaryFile info2( info2Path ); //検索 std::string restoreString = restoreFile(); char* pInfo2 = reinterpret_cast< char* >( info2() ); char* pInfo2End = pInfo2 + info2.GetSize(); char* pFilePosition = std::search( pInfo2, pInfo2End, restoreString.begin(), restoreString.end() ); TB_ENFORCE( TrueFail(), pFilePosition == pInfo2End ); //見つかった。パスの後にNULLが連続していて、その後にファイルの番号が来る。 pFilePosition += restoreString.length(); while( pFilePosition < pInfo2End && '\0' == pFilePosition[0] ) ++pFilePosition; //ごみ箱内からIDを検索する std::string id = String( *reinterpret_cast< Uint16* >( pFilePosition ) )(); FilePath source; TB_FOR_EACH( std::vector< FilePath >, paths ) { std::string basename = it->GetBaseName(); std::string::size_type index = basename.find( id ); if( std::string::npos == index ) continue; //Dc198.lzhで、9番がヒットするのを防ぐ。 //見つけた位置にIDの長さを加えたらベース名の長さになること。 if( basename.length() != index + id.length() ) continue; //ありえるのかわからないけど、ファイル名部分がIDと一緒ならいいとする。 //198.lzhみたいな。 if( basename.length() != id.length() ) { //IDが見つかった位置はベース名の最後。 //サイズが違うのならindexは0以上。 //index-1が数字だったらやり直す。 //98のときに198.lzhみたいな。 if( '0' <= basename[index-1] && basename[index-1] <= '9' ) continue; } //ここまでくれば見つかったことになる。 source = *it; break; } //元に戻す FileSystem::Move( source, restoreFile ); }
| 固定リンク | コメント (0) | トラックバック (0)
{
HDSKSPC hDiskSpace = SetupCreateDiskSpaceList( NULL, NULL, SPDSL_IGNORE_DISK );
SetupAddToDiskSpaceList( hDiskSpace, path().c_str(), GetSize( path ), FILEOP_COPY, NULL, NULL );
LONGLONG size;
SetupQuerySpaceRequiredOnDrive( hDiskSpace, path.GetDriveLetter().c_str(), &size, NULL, NULL );
SetupDestroyDiskSpaceList( hDiskSpace );
}「サイズ」はGetFileSizeで取得できるように思うが、実際にはこの関数はそれほど性能がよくない。{
const char* pFolder = "c:\\*";
const char* pFileName = "test.txt";
const char* pFullPath = "c:\\test.txt";
WIN32_FIND_DATA findData;
HANDLE hFind = FindFirstFile(pFullPath,&findData);
if( hFind != INVALID_HANDLE_VALUE )
{
FindClose( hFind );
return findData.nFileSizeHigh*MAXDWORD+findData.nFileSizeLow;
}
else
{
//FindFirstFileではだめなのに、FindNextFileだと見つかる場合がある。ものすっごく謎。
//アクセス権がないファイルの場合などに起こるみたいな気がする。
hFind = FindFirstFile( pFolder, &findData );
for( BOOL result = TRUE; result; result = FindNextFile( hFind, &findData ) )
{
if( lstrcmp( pFileName, findData.cFileName ) == 0 )
{
FindClose( hFind );
return findData.nFileSizeHigh*MAXDWORD+findData.nFileSizeLow;
}
}
//なければエラー
FindClose( hFind );
assert( !"ファイルが見つかりませんでした。" );
return 0;
}
}ちゃんとやろうとすればするほどコードが長くなるというお話。
class A { public: virtual ~A() throw(){} };
class A{ public: ~A(){ assert(0); } }; class B : public A{}; { B b; }
class A{ public: virtual ~A(){ throw 0; } }; try { A a5; { A a4; { A a3; { A a2; { A a1; } //1 } } } } catch( int& i ) { //2 }
BOOST_STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer);<br>で
#ifdef BOOST_MSVC BOOST_STATIC_CONSTANT(bool, check = !std::numeric_limits::is_integer); BOOST_STATIC_ASSERT(check); #else BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); #endif
for( int index = MDIChildCount-1; index >= 0; --index ) MDIChildren[index]->Close();
すでにどれかのサーフェィスに関連付けられていると失敗する。
サーフェィスを先に解放するかIDirectDrawSurface::SetClipperでNULLを渡してクリッパを解除すること。
cvs server: cannot open (...): Permission denied protocol error: directory '(...)' not within root '(...)'その場合、上記のnot within root '(...)'の(...)部分のパス区切り文字は、directory '(...)'の(...)部分のパス区切り文字と同一だろうか。
HWND hWnd; //hWndに対象のウインドウハンドルを取得。 //対象の拡張スタイルを取得 LONG style = GetWindowLong(hWnd, GWL_EXSTYLE); //半透明化フラグを追加。 style |= WS_EX_LAYERED; //エラーフラグをクリア SetLastError(0); //拡張スタイルをセット if(!SetWindowLong(hWnd, GWL_EXSTYLE, style)) { //戻り値が0。エラーフラグを確認 if( GetLastError() != 0 ) assert(0); //エラーフラグが0以外ならエラー } //確認のため LONG style2 = GetWindowLong(hWnd, GWL_EXSTYLE); assert( style == style2 ); //…のはず。上記のソースでassert(0)にはならない(つまりSetWindowLongは成功している)くせにassert( style == style2 );は成立しません。(もともとWS_EX_LAYEREDフラグがたっていないとした場合。)
style &= ~WS_EX_CLIENTEDGE;という風に、他のフラグをいじった場合は普通に動作します。
style &= ~WS_EX_CLIENTEDGE; style |= WS_EX_LAYERED;と、他のフラグと一緒にいじると他のフラグごとSetWindowLongは無視します。つまりWS_EX_LAYEREDを子ウインドウに設定しようとするとSetWindowLongは無視するわけです。
template< typename T > class X{}; class A : public X< A > { };これは合法。
class B{}; template< typename T > class X{}; template< typename U > class A : public X< A< B > > {};これも合法。
template< typename T > class X{}; template< typename U > class A : public X< A< X < ... > > > {};こう、順を追って行けばわかりやすいけどいきなり最後のが出てきたりして、AやXのテンプレート引数が4つも5つもあるとそろそろ死ねる。
#include <windows.h> template< typename T > class A { public: template< typename U > void foo( A<U> pU ); }; template< typename T > template< typename U > inline void A<T>::foo( A<U> pU ) { int t = 0; } int __stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) { A<int> a; A<char>().foo( a ); return 0; }俺は今まで
template< typename T, typename U > inline void A<T>::foo( A<U> pU ) { int t = 0; }こう書くもんだと思ってたんですが実は
template< typename T > template< typename U > inline void A<T>::foo( A<U> pU ) { int t = 0; }こうらしいですね。
見やすいLaTeXのコマンドリファレンスってあんまないですよね。
LaTeXしよう!
TeX書くならここみると便利。たいていのコマンドのってます。
| 固定リンク | コメント (0) | トラックバック (0)
#include <stdio.h> #include <time.h> //////////////////////////////////////////////////////////////////////////////// void a() { for( int i = 0; i < 1000000000; ++i ); } //////////////////////////////////////////////////////////////////////////////// void b() { for( int i = 0; i < 100000000; ++i ); } //////////////////////////////////////////////////////////////////////////////// int main() { clock_t last = clock(); a(); double span = clock() - last; printf( "%f", span / CLOCKS_PER_SEC ); last = clock(); b(); span = clock() - last; printf( "%f", span / CLOCKS_PER_SEC ); return 0; } ////////////////////////////////////////////////////////////////////////////////
| 固定リンク | コメント (0) | トラックバック (0)
class A { public: virtual ~A(){} }; class C { public: virtual ~C(){} }; class B : public A, public C {}; int __stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) { B* pB = new B; A* pA = pB; C* pC = pB; //pAとpCはアドレスが異なる!! size_t b = sizeof(B); size_t c = sizeof(C); delete pA; }このコードでは実際にそれを検証している。
| + | pA | 0x00372f88 | A * |
| + | pB | 0x00372f88 | B * |
| + | pC | 0x00372f8c | C * |
| b | 8 | unsigned int | |
| c | 4 | unsigned int |
|372f88-------------B:8-----------------| +----+----+----+----+----+----+----+----+ |372f8c----C:4------|このようにBはCを含んでいる。
| 固定リンク | コメント (0) | トラックバック (0)
#include <windows.h> #include <crtdbg.h> //////////////////////////////////////////////////////////////////////////////// int __stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) { _CrtSetDbgFlag( _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_CHECK_CRT_DF ); return 0L; } ////////////////////////////////////////////////////////////////////////////////上記のコードでやってみたんですが、結果は
Detected memory leaks!
Dumping objects ->
_file.c(137) : {42} crt block at 0x003707B0, subtype 0, 2048 bytes long.
Data: < ~B B 0 B P B > F0 7E 42 00 10 7F 42 00 30 7F 42 00 50 7F 42 00
onexit.c(198) : {41} crt block at 0x00372EC8, subtype 0, 128 bytes long.
Data: < A > C3 10 41 00 CD CD CD CD CD CD CD CD CD CD CD CD
stdenvp.c(130) : {40} crt block at 0x00372BF8, subtype 0, 654 bytes long.
Data: <_ACP_PATH=C:\Pro> 5F 41 43 50 5F 50 41 54 48 3D 43 3A 5C 50 72 6F
:
stdenvp.c(117) : {4} crt block at 0x003716F0, subtype 0, 148 bytes long.
Data: < 7 0 7 7 ( 7 > C0 17 37 00 30 18 37 00 B8 18 37 00 28 19 37 00
stdargv.c(130) : {3} crt block at 0x00371648, subtype 0, 102 bytes long.
Data: <P 7 c:\docum> 50 16 37 00 00 00 00 00 63 3A 5C 64 6F 63 75 6D
ioinit.c(130) : {1} crt block at 0x00370670, subtype 0, 256 bytes long.
Data: < > FF FF FF FF C1 0A CD CD FF FF FF FF C1 0A CD CD
Object dump complete.はぁ?って感じですが。#include <time.h> #include <stdio.h> { //timeでシステム時刻を得る。 time_t t = time( NULL ); //localtimeでtm構造体を得る。 /* struct tm { int tm_sec; /* seconds after the minute - [0,59] */ int tm_min; /* minutes after the hour - [0,59] */ int tm_hour; /* hours since midnight - [0,23] */ int tm_mday; /* day of the month - [1,31] */ int tm_mon; /* months since January - [0,11] */ int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday - [0,6] */ int tm_yday; /* days since January 1 - [0,365] */ int tm_isdst; /* daylight savings time flag */ }; */ tm* pTM = localtime( &t ); //tm構造体のデータをsprintfに通して文字列にする。 char timeString[256]; sprintf( timeString, "%02d/%02d/%02d %02d:%02d", pTM->tm_year%100, pTM->tm_mon, pTM->tm_mday, pTM->tm_hour, pTM->tm_min ); }
{
FILE* pFile = fopen(...);
if( ! pFile )
;//エラー処理。例外投げるとか。returnで関数を終わるとか。
//以下通常の処理。
}みたいな感じで書きます。if文を使ってエラーが起こったら回復処理を行うといった感じ。DirectDraw::DirectDraw( ... )
{
if( DirectDrawCreate( NULL, &lpDirectDraw, NULL ) != DD_OK )
return;
//プライマリ作るんでまず強調レベルを普通にセットする。
if( lpDirectDraw->SetCooperativeLevel( hWnd, DDSCL_NORMAL ) )
return;
bool bResult = false;
lpPrimary = new PrimarySurface( bResult, lpDirectDraw, rScreen );
if( !bResult )
return;
if( bFullScreen )
lpMode = new FullScreenMode( bResult, hWnd, lpDirectDraw );
else
lpMode = new WindowMode( bResult, hWnd, lpDirectDraw, lpPrimary->GetSurface() );
if( !bResult )
return;
if( !SetDisplayMode( iWidth, iHeight, iColorDepth, bFullScreen ) )
return;
lpSecondary = new TemporarySurface( bResult, lpDirectDraw, iWidth, iHeight );
if( !bResult )
return;
}はるか昔に書いたDirectDrawの初期化部分なんですが、こんなふーに1文書くごとにif文が挟まってます。DirectDraw::DirectDraw( ... )
{
DirectDrawCreate( NULL, &lpDirectDraw, NULL );
lpDirectDraw->SetCooperativeLevel( hWnd, DDSCL_NORMAL );
lpPrimary = new PrimarySurface( bResult, lpDirectDraw, rScreen );
if( bFullScreen )
lpMode = new FullScreenMode( bResult, hWnd, lpDirectDraw );
else
lpMode = new WindowMode( bResult, hWnd, lpDirectDraw, lpPrimary->GetSurface() );
SetDisplayMode( iWidth, iHeight, iColorDepth, bFullScreen );
lpSecondary = new TemporarySurface( bResult, lpDirectDraw, iWidth, iHeight );
}後者の方が何やってるか見通しがいいような気がしませんか?bool foo();と言う関数があって、戻り値がfalseなら例外Exceptionを投げるようなエラー処理を行いたいとします。{
if( ! foo() )
throw Exception();
}Andrei先生は以下のような関数Enforceを導入したらどうかと提案しています。 template< typename tException > inline void Enforce( bool isCondition ) { if( !isCondition ) throw tException(); }これを使うと、
{
Enforce< Exception >( foo() );
}とまぁ、こんな感じ。とりあえず1行にまとまります。{
if( ! foo() )
throw Exception();
if( ! foo() )
throw Exception();
if( ! foo() )
throw Exception();
if( ! foo() )
throw Exception();
if( ! foo() )
throw Exception();
if( ! foo() )
throw Exception();
if( ! foo() )
throw Exception();
}こう書くのと {
Enforce< Exception >( foo() );
Enforce< Exception >( foo() );
Enforce< Exception >( foo() );
Enforce< Exception >( foo() );
Enforce< Exception >( foo() );
Enforce< Exception >( foo() );
Enforce< Exception >( foo() );
Enforce< Exception >( foo() );
}こう書くの、どちらが本来の処理の流れが見やすいだろうか、と。{
FILE* pFile = fopen(...);
if( ! pFile )
;//エラー処理。例外投げるとか。returnで関数を終わるとか。
//以下通常の処理。
}この処理を考えてみましょう。{
FILE* pFile = fopen(...);
Enforce< Exception >( pFile );
//以下通常の処理。
}となってしまい芸がありません。template< typename tException, typename tArgument > inline tArgument& Enforce( tArgument& argument ) { if( !argument ) throw tException(); }引数に受け取った値をそのまま戻り値として返す、「パイプ」のような関数になりました。
{
FILE* pFile = Enforce< Exception >( fopen(...) );
//以下通常の処理。
}見事にfopenのエラー処理をenforceにまとめることができます。
Enforce< HandlerPledicate, Exception >( fopen(...) )とかって感じ。
Enforce< Exception >( fopen(...) ) << "fopen failed.\nfilename : " << __FILE__ << "\nline : "__LINE__ << endl;
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
割と知らない人もいるようなのでメモ。
.cppじゃなくて.cという拡張子にしてファイルをVCのプロジェクトに追加するとCの文法でコンパイルしてくれます。たとえば変数をスコープの先頭におかないとコンパイルエラーになります。
| 固定リンク | コメント (0) | トラックバック (0)
#include <stdio.h> #include <conio.h> int main() { printf( "Hit any key...\n" ); while( !_kbhit() ); return 0; }
そもそもの始まりは謎のパーティションの分け方だった。
2つのHDDがパソに刺さっていた。
そしてCドライブとDドライブがそのシステムにはあった。
ここまでは普通だ。
Cドライブは1つ目のHDDの前半分と2つ目のHDDの前半分で構成されていて、
Dドライブは1つ目のHDDの後半分と2つ目のHDDの後半分で構成されていた。
は?
どーりでCドライブからDドライブへのコピーが鬼のように遅いわけである。
つーわけでDドラのバックアップの中で重要そうなのを俺のノートにコピって論理ドライブを削除することにした。
Windows2000のCDでブートして4つある論理ドライブをすべて削除する。
論理ドライブっつーのは削除すると未使用領域になる。
ふつう、物理ドライブ中に2つの論理ドライブがあって、それを2つとも削除すると1つの未使用領域ができる。
2つの論理ドライブを削除したからといって2つの未使用領域ができたりはしない。
2つのドライブ中の計4つの論理ドライブを削除したら計6個の未使用領域ができた。
謎。
何が困るって要するに1つのドライブが3つに分割されてしまってるので、たとえば10GのHDDならCドライブに最大3Gしか割り当てられない。
ふつうは未使用領域は1つしかない。すべての未使用領域は1つに統合されるのだが。
とにかくこの3×2の未使用領域を1つにまとめなければならない。
再起動しても分かれたまま。むしろどういう仕組みなのか知りたい。
結局、適当な未使用領域の中に適当な大きさのパティーションを作って、それを消したら未使用領域が1つになった。
謎の連続だった。
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
DMonkeyはDelphiのコンポーネントでDelphiで作るプログラムに簡単にスクリプト機能を追加できるもの。
IriaやIrvineの作者さんが作ってます。
Irvineの遺跡
DMonkey Download
Irvineスクリプトっていろいろできるのにあんま作られてないよなーとか。
以下ではそのDMonkeyで以前であった謎現象をご紹介。とはいえ03/02/08でのことなので最新版では改善されてるかも。
while( true ) { try { break; WScript.Echo(); } catch( e ) { } }Echoが実行される。
for( index = irvine.ItemCount - 1; 0 <= index; --index ) { if( irvine.Current.Items[index].Data.indexOf( url ) == 0 ) break; }breakのあとに--indexが実行される。
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
Delphi で作られるソフトすべてでこの問題が発生します。ちなみに、Delphi 自身も同じ問題を抱えています。
アプリケーションのクラスアイコンをセットしたら表示されるようになると思います。
プロジェクトソースかメインフォームの OnCreate イベントで、
SetClassLong(Application.Handle,
GCL_HICON,
Application.Icon.Handle);
を実行して下さい。
ref: http://www2.big.or.jp/~osamu/Delphi/Tips/key.cgi?key=28
| 固定リンク | コメント (0) | トラックバック (0)
Ctrl+Capsを気持ち長めに押してみよう。
どうも入力のタイミングがシビアらしくなかなか認識しないが、気長に20回くらいは試すとたいてい元に戻る。元に戻ったのに気づかないで連打してるとまた半角カナになるから要注意。
それでもだめならキーボードドライバを削除して再起動で直ることも。
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
| 固定リンク | コメント (0) | トラックバック (0)
Panel p = new Panel();
Button b = new Button();
b.setSize( 10, 10 );
addToContainer( p, b );
void addToContainer( Container aContainer, Component aComponent )
{
//LayoutManagerが設定されているContainerにaddすると、addしたItemのSize情報が無視されてしまうので、
//いったんLayoutManagerを設定していないPanelを作って、それからaddするというめんどくさいことをしないといけない。
Panel panel = new Panel( null );
panel.setSize( aComponent.getSize() );
panel.add( aComponent );
aContainer.add( panel );
}
class RedFilter extends RGBImageFilter { public int filterRGB( int x, int y, int rgb ) { return 0x99000000 | (rgb & 0x00ffffff); // アルファ値は 0x99 } } public class Animation extends Applet { Image mImage; public void init() { mImage = getImage( getCodeBase(), "Res\\A.jpg" ); mImage = createImage( new FilteredImageSource( mImage.getSource(), new RedFilter() ) ); } public void paint( Graphics aGraphic ) { aGraphic.drawImage( mImage, 0, 0, this ); } }
ウェブログ・ココログ関連 | ゲーム | パソコン・インターネット | 学問・資格 | 日記・コラム・つぶやき
最近のコメント