VC,VC++ 関連回答6
スクリーンセーバの窓にWM_MOUSEMOVEを送って
やれば(念のため100ピクセル分ぐらい)たいてい
いけます.
ただ,マウスが動いても終了しないような特殊
な目的のスクリーンセーバの場合は対処できな
いので,完全ではありませんが・・・それにパ
スワードが設定してあったりする場合もだめで
すし.
プロセスを強制的にキルできればそれが一番確
実かも(^^;
#強制終了のさせかたはしりませんm(__)m
<Q1>に対する回答2
> スクリーンセーバの窓にWM_MOUSEMOVEを送って
> やれば(念のため100ピクセル分ぐらい)たいてい
> いけます.
スクリーンセーバの窓へメッセージを送るには
次の方法でいいのでしょうか?
::PostMessage( GetForegroundWindow(), WM_MOUSEMOVE, 0, 0 );
また、100ピクセルは wParam, lParamの
どちらに代入すればいいのでしょうか?
Windowsのプログラムはこれが最初ですので、
初歩的な質問で申し訳ありません。
> ただ,マウスが動いても終了しないような特殊
> な目的のスクリーンセーバの場合は対処できな
> いので,完全ではありませんが・・・それにパ
> スワードが設定してあったりする場合もだめで
> すし.
> プロセスを強制的にキルできればそれが一番確
> 実かも(^^;
> #強制終了のさせかたはしりませんm(__)m
マウスが動いた時はスクリーンセーバが終了してもかまいません。
また、パスワードは使用しない事になっています。
最初から初歩的な質問ばかりで申し訳ありませんが、
ご援助のほどよろしくお願い致します。
<Q1>に対する回答3
>次の方法でいいのでしょうか?
> ::PostMessage( GetForegroundWindow(), WM_MOUSEMOVE, 0, 0 );
おそらくは・・・
そのスクリーンセーバのウィンドウ名が分かっ
ているならばそれで探すべきですが,分からな
いならばそうするしかないかと思います.
っていうか,試してみていただけます?(^^;
#そうすりゃ一発で可否が分かりますんで・・・
> また、100ピクセルは wParam, lParamの
>どちらに代入すればいいのでしょうか?
どっちでも良いです.念のため100ピクセルっ
てのは,数ピクセルの動きだと終了しないよう
になってるスクリーンセーバもあるからです.
あ,それとWM_MOUSEMOVEは2,3回送ったほうが
良いですね.同じように1回のWM_MOUSEMOVEで
は終了しないようになってるスクリーンセーバ
もありますので.
>> ただ,マウスが動いても終了しないような特殊
>> な目的のスクリーンセーバの場合は対処できな
>> いので,完全ではありませんが・・・それにパ
>> スワードが設定してあったりする場合もだめで
>> すし.
> マウスが動いた時はスクリーンセーバが終了してもかまいません。
あー・・・っていうか,終了してもかまわない
か,ということではなくて,んー,例が挙げられ
なくて困ってるんですが,スクリーンセーバ型の
WWWブラウザで,マウスでクリックしたりして操
作出来るようになってて(マウスの動きでは終了
しないという事),設定した特定のキー操作で終
了する(例えばESCで終了とか)ようなソフトがあ
ったと思うんです.
ですから,そういった通常の方方では終了しな
いタイプのスクリーンセーバには対処できません,
ということです.
> また、パスワードは使用しない事になっています。
ということは,スクリーンセーバは特定されて
るんでしょうか?それならば話は簡単ですが・・・
<Q1>に対する回答4
Win32であれば、もっと簡単にmouse_event()でOKです。
<Q1>に対する回答5
自分はVB2.0とWin3.1の環境ですが同じ事を行いました。
自分の場合はSendKeyでキーを送って解除したのですが、
斉藤さんが書かれていたとおりマウスイベントを送っても大丈夫だと思います。
あと、プロテクトモードの場合ですがSendKeyする前に、
WritePrivateProfileString(VB2.0の場合ですが)でCTOROL.INI内の
起動中のスクリーンセーバの[PWProtected]の値を"0"にしてからSendKeyすれば解除
できます。
ただし、この場合もプロテクトモードのパスワードを入力するダイアログボックス
が
表示されているとうまくいきません。
そこで、皆さんのお力を借りたいのですが、
このダイアログボックスが表示されているかどうかを知りたいのですが、
どのようにすればよろしいのでしょうか?
どなたかご存知の方お力をお貸しください。
よろしくお願いします。
CMainFrame::PreCreateWindow() で、cs.hMenu = NULL とすると良いのではないでし
ょうか。
warning じゃなくてエラーが出るんですか?
エラーの内容も書かないとよくわからないですけど、CString には int からの変
換って無いから、ここではきっと char に変換されてるはずですね。
おそらくそのときの warning なんじゃないでしょうか?
そうじゃないにしても、このやりかたじゃ cost の値を表示させる事は出来ませ
んよ。sprintf とかを使いましょう。
<Q3>に対する回答2
VC4.0以上なら、
CString strCost; と文字列オブジェクトを用意して
strCost.Format("%d", cost);
とやれば、cost の数値(int 型)が文字列(CString)になります。
これを SetWindowText に渡してやればOKですよ。
4.0 以前だったら、XXXさんの言うとおり
sprintf が手っ取り早いですね。
GetActiveView()じゃだめ?
<Q4>に対する回答2
Viewが1枚なら CView* CFrameWnd::GetActiveView() Const;
というのがあります。
Viewが複数枚でしたら・・・、App クラスのメンバにポインタ変数
をとっておいて、Viewを生成する毎にそこに代入(強引すぎます?)。
MFCを使っておられるのでしょうか? だったら、CDialogのインスタンスを自
動変数として使っていませんか? だったら、DLLの関数から戻るときにCDialog
のインスタンスのデストラクタが呼び出されるので,ダイアログが消えてしまう
のは当然だと思います。
<Q5>に対する回答2
これは XXXさんからいただいた回答です。
以下の方法にて解決することができました。有難うございました。
> VC++で作成したDLL内で、モードレスダイアログを作成したいのですが、
> どなたか御存知の方がおられましたら、教えて下さい。
>
> モーダルダイアログは作制できるのですが、Create関数を使って作成し
> うとすると、一時的にダイアログが表示され、DLLの関数から帰って
> くると消えてしまいます。
>
> MFCを使用していると仮定しますが、CDialogをローカル変数として宣言し
> てないでしょうか?
>
> foo()
> {
> CDialog dlg;
> dlg.Create...
> }
>
> この様にした場合、関数fooから抜けるときにdlgが破棄され、デストラク
> タでダイアログが消されます。
> モーダルは普通、関数内でダイアログが消されるので問題無いのだと思い
> ます。
>
> 回避方法としては、CDialogを呼び出し側で作成するか(それだと多分DLLの
> 意味が無いですね)、ローカルではなくスタティックまたはnewするのがいい
> と思います。newした場合は誰がdeleteするかが問題になりますが...
>
> モードレスを作成する関数と削除する関数がDLLにあるなら、
>
> static CDialog dlg;
> foo() // 作成する
> {
> dlg.Create...
> }
> boo() // 削除する
> {
> dlg.DestoryWindow...
> }
> ----- または -----
> CDialog *p; // グローバル変数
>
> foo() // 作成する
> {
> p = new CDialog;
> p->Create...
> }
>
> boo() // 削除する
> {
> p->DestoryWindow....
> delete p;
> }
>
> という感じにすればいいと思います。
> # このままだとfooを2回呼ぶとおかしくなりますが...r^^;
> 無いので困っています。参考書を探したのですが、シリアル通信の説明は
> 載っていても、パラレルについては載っていませんでした。
私も本屋を歩き回って探したんですけど、見つけられませんでした。
たいてい、「シリアルもパラレルも扱える。」としか書いてなくて、
サンプルはシリアルだけ、というパターンですね。
> シリアル通信と同じで、CeateFile,ReadFile,WriteFile等のAPIを使えば可能
> なのでしょうか?それとも、inp/outを使わなければならないのでしょうか?
> (この場合、NTでは動かないだろうけど・・・)
CreateFile,ReadFile,WriteFile なんですけど、
私のやり方が間違っていたのかうまくいきませんでした。
#プリンタドライバが組み込まれてる時に、
#出来るのかなぁ、と思っています。
で結局ターゲットが Windows95 だったので
インラインアセンブラで in/out してます。
<Q6>に対する回答2
> たいてい、「シリアルもパラレルも扱える。」としか書いてなくて、
> サンプルはシリアルだけ、というパターンですね。
その通りです。
VCのサンプルもシリアルだけだし。
> CreateFile,ReadFile,WriteFile なんですけど、
> 私のやり方が間違っていたのかうまくいきませんでした。
> #プリンタドライバが組み込まれてる時に、
> #出来るのかなぁ、と思っています。
> で結局ターゲットが Windows95 だったので
> インラインアセンブラで in/out してます。
その方がいいみたいですね。
とりあえず、NTでの動作はあきらめます。
<Q6>に対する回答3
????File 系の API を悪者扱いしましたが、
私の場合、通信相手とは *ハンドシェーク無し* だったので、
うまくいかなかったのだと思います。
混乱させてしまって申し訳ありません。
API を使えるならその方が良いと思います。
#私も NT 使ってるので、動作確認が面倒でした。
> BOOL C***::PreTranslateMessage(MSG* pMsg)
> {
> if(pMsg->message == VK_RETURN){
> SendMessage(WM_NEXTDLGCTL, 0, 0);
このタイミングで、 return TRUE;が必要なのでは?
<Q7>に対する回答2
いいえ、問題はそんなに単純なことではなくて、
デバッガを使ってみると、SendMessageの行に入ってこないのです。
つまりpMsg->message == VK_RETURNという式は、
いつまでたっても’偽’なままだとおもうのです。
<Q7>に対する回答3
仮想キーコードは、wParamに入ってくるはずです。
メッセージでチェックするのであれば、
if(pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
でチェックしないといけないと思います。
<Q7>に対する回答4
結局
BOOL C***::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->wParam == VK_RETURN){ //ENTERキーが押されたか?
SendMessage(WM_NEXTDLGCTL, 0, 0); //次にフォーカスを移す
pMsg->message = WM_NULL; //ENTERキーの無効化
}
return CDialog::PreTranslateMessage(pMsg);
}
というコードで解決しました。
But!
例えばエディット内で文字を変換する。
そしてとにかく変換を繰り返して目的の文字を発見して、ENTERキーを押すと
、
フォーカスも一緒に移動してしまうので上のコードですべてうまく解決はしません。
皆さん注意しましょう。
<Q7>に対する回答5
それならば、なんとか工夫して、
OnOk で処理させるというのはどーでしょうか?
// あれ? OK button が押されたときに呼ばれる関数って OnOK でしたっけ?
それが起きる原因は、PreTranslateMessage で処理させていることなのですから、
こうすれば解決できると思います。
// あー、もっと簡単に、
// WM_CHAR で '\r' か '\n' が来るのを捕捉するという手もあるか。
// でもこれだと先に OnOk が呼ばれちゃうのかな。
とりあえず片方だけですが、
| ボタンへのビットマップの貼り付け方法をお聞き
| したいんですが。
(略)
| 2.CButtonクラスのメンバ関数SetBitmap()を使う。
(略)
| 2.の方は、うまく動いてくれません。コーディングは、
| OnInitDialog 関数内で以下の様にしています。
|
| {
| CBitmap Bitmap;
| CButton *Button;
| HBITMAP x;
|
| Bitmap.LoadBitmap(IDB_BITMAP1);
| x = HBITMAP(Bitmap);
| Button = (CButton*)GetDlgItem(IDC_BUTTON2);
| Button->SetBitmap(x);
| }
CButtonのスタイルにBS_BITMAPを指定しないとSetBitmapは効かなかった
と思います。(MFC 4.2の場合)
指定するにはダイアログエディタで、そのボタンのプロパティで
[スタイル]の[ビットマップ]をチェックしてみてください。
#MFC4.0のときはBS_BITMAPを指定してもうまくいかなかったような気がする…。
#だからOwner Drawでごまかしたような気が…。
<Q8>に対する回答2
CButtonがスコープから抜ける時にデストラクタでCButton::De
leteObjectが呼び出されます。(ビットマップハンドルが無効になる。)
{
HBITMAP hbm;
CButton *Button;
hbm = ::LoadBitmap(MAKEINTRESOURCE(IDB_BITMAP1));
Button = (CButton*)GetDlgItem(IDC_BUTTON2);
hbm = Button->SetBitmap(hbm);
if(hbm) ::DeleteObject(hbm);
}
でいいのでは?
おそらく、プロジェクトタイプを「コンソールアプリケーション」として作成するべ
きところを「(Windows) アプリケーション」として作成されているのでしょう。
# ちなみにこの場合、未解決のシンボルは WinMain() のはず
プロジェクトタイプを「コンソールアプリケーション」として、作成し直してみては
いかがでしょうか。
<Q9>に対する回答2
wmain() って、C の RuntTime に含まれているんですねぇ。
たまたま自分のプログラムのデバッグをしていたら、出会いました。
# だからどうしたという性質のものでもないんですが (^^;
<Q9>に対する回答3
wmain って UNICODE 版の main のような気がしますけど?
buildの設定がなんか違うのではないのでしょうか?
main の場合も同様に console アプリケーションとして
build すべきだとおもいます。
...ひょっとして、 UNICODE 版の Libraryが無いとかでしょうか?
#セットアップにそんなオプションあったかな?
Windows 95 + VC++4.2EE ですが ,当該ソースを
そのまんま Microsoft の Web から、Cut & Paste して、
環境変数の path / include / lib を適切に設定して
以下のようにしたら通りましたよ?
cl q151546.c netapi32.lib
#netapi32.lib は、wmain の関係者じゃありません 念のため。
#そんな事無いと思いますが...
あと考えられるのは C++ のリンケージでオブジェクトが生成されているとか?
ソースの拡張子が .cpp / cxx の場合拡張子を C にするか
extern "C" int wmain()
{
}
とかやってみるとうまく行くのかもしれません。
#ちょっと自信無しです。
<Q9>に対する回答4
> wmain() って、C の RuntTime に含まれているんですねぇ。
> たまたま自分のプログラムのデバッグをしていたら、出会いました。
さらに茶々っ。
ふつーは、start-up code を眺めていたら出会う、でしょう(^^;。
wmain って、なんだー、とか思いつつ grep wmain して、
#ifdef UNICODE なら main が wmain になることを知るのです(^^;。
そーいえば、argv も UNICODE になっているのだろうか?
>wmain って UNICODE 版の main のような気がしますけど?
>buildの設定がなんか違うのではないのでしょうか?
たまたまどこかで
#define UNICODE
されていた、の一点読みっす。
<Q9>に対する回答5
掲題の件で色々な方から教えていただき大変助かりました。
【wmain】
ポイントは、
「file.cpp ではなく file.c にする。」
でした。
file.cpp にすると、
-----
LIBCD.lib(wcrt0.obj) : error LNK2001: 外部シンンボル "_wmain" は未解決です
-----
とエラーが出ます。
が、このソースのファイル名を、file.c にするとOKでした。
#う〜ん。なんで?(^^;
【NET USER】
>OKのような気がしますが、NTでは、コマンド
>ライン(DOSプロンプト)でパスワードの変更が
>行えません。
ですが、NT で NET USER というコマンドがあります。
これでパスワード変更を行うと、
-----
C:\>net user USERNAME PASSWORD /domain
この要求はドメイン DOMAIN-A のプライマリマリドメインコントローラで処理されます。
システムエラー 5 が発生しました。
アクセスが拒否されました。
-----
と表示されてしまいます。
NET USER コマンドの使い方が間違っているのでしょうか?
どなたかご存知のかた、教えてくださいませ。
#どこかに、Not Implemented って書いてあったような
#気がしたので、てっきり NET USER コマンドは使えな
#いものだと勘違いしていました。(^^;
ちなみに、[ALT+CTRL+DEL] ではちゃんとパスワード変更が
行えます。
<Q9>に対する回答6
>#ifdef UNICODE なら main が wmain になることを知るのです(^^;。
たまたま今まで、Win32 環境で main() より後までデバッガで追ったことが無かったみたいです (^^;
>そーいえば、argv も UNICODE になっているのだろうか?
やってみたことはないですけど、DBCS のファイル名を受け取る場合を考えると、 UNICODE になってそうですね。
>>wmain って UNICODE 版の main のような気がしますけど?
>>buildの設定がなんか違うのではないのでしょうか?
>
>たまたまどこかで
>#define UNICODE
>されていた、の一点読みっす。
元記事の原因はそっちかな?
.cpp -> .c で現象が変わるのは、プリコンパイルヘッダにごみが残っていたとか?
<Q9>に対する回答7
> 元記事の原因はそっちかな?
私も、最初そうかなと思ったんですが、元記事で出ている kb のサンプルを見てみると、
しっかり wmain ()が記述されているんですよ。
当該ソース関数が定義されてて、リンク時に "_wmainが未解決です。"
みたいなエラーが出るのなら、C++ の時のシンボル名の修飾が原因で
リンク 時に、.obj に格納されているシンボル名の不一致が起こったんじゃ
無いかと思ったんで #2091 のように書いてみました。
> .cpp -> .c で現象が変わるのは、プリコンパイルヘッダにごみが残っていたとか?
>
私は、 .pch を使わないのですが、拡張子を .cpp に変更してコンパイル/リンクするだけで、
リンクエラーが出ますね。
#でも、うちの環境だと、拡張子を.cppにしたら、
#「外部シンボル_main が未解決です。」というエラーになっちゃいました。
#そうすると、別の現象かな?
先ほど 拡張子を .c と .cppとで それぞれコンパイルし、できた
.obj をダンプして、wmain のシンボル名を調べてみた所、
以下のように異なっていました。
ext | symbol
-----+-------
.c | _wmain
.cpp | ?wmain@@YAHHQAPAG@Z
もう一つ付け加えると、.cpp の時に、
extern "C" int __cdecl wmain( )
としたら無事にリンクが通りました。
#そうするとヘッダ/ライブラリのバグかな?
>MFCにそのような判定や、文字コードを変換するような関数はあるのでしょうか
>?
MFC には無いと思います。
>もし、MFCに無くてもAPIにあるというのであればどのようなものがあるのでしょ
>うか?
辛うじて、C のランタイムに SJIS <=> JIS くらいはあったと思いますが、
(お仕事用途だと)基本的に自作することになるのではないでしょうか。
<Q10>に対する回答2
UNIX用のプログラムだとソース公開されてるの
が多いので,参考になるんじゃないでしょうか.
#ただし,著作権には注意です:-P
「インターネット」って、確か、
実体を持たない仮想folder(という言い方でいいんだっけ?)ですよね。
link file みたいな、実体の file があるものと区別できれば
うまく整順できるんじゃないでしょーか。
区別する方法は...、直接的なのは思いつかない...。
// ITEMIDLIST から SHGetPathFromIDList できるかどうかを調べるとか(^^;。
// にがすぎる方法だなぁ。
<Q11>に対する回答2
>「インターネット」って、確か、
>実体を持たない仮想folder(という言い方でいいんだっけ?)ですよね。
知りませんでした。
だから、エクスプローラーでシステムフォルダという種類に
分別されてたんですね。
>// ITEMIDLIST から SHGetPathFromIDList できるかどうかを調べるとか(^^;。
>// にがすぎる方法だなぁ。
この方法で、やってみました。
とりあえず、結果は上手く行っていますが、スピードを要求される部分で
不具合が出ないか、目下テスト中です。
<Q11>に対する回答3
SHGetFileInfo() で、SHGFI_ATTRIBUTES を指定し、
SFGAO_FILESYSTEMかどうかを確かめる事でも判別可能でした。
<Q11>に対する回答4
SHGetFileInfo() って、path を引数にとるんじゃなかったのかな、
と思いつつ help を見ると...、
なにー、こんな汚い cast をしろというのかぁー、ずぎゃ。
とりあえず、使う時には、関数の多重定義で乗り切ることにしました。
いや、でも、勘違いしていたので、有用なことを聞きました。
ほかにこんな不条理な関数はありませんよね?
<Q11>に対する回答5
それじゃ、全然役に立ちませんね(爆)
現在、趣味の人向けで、一番役に立ちそうな参考書は、
BC++builderのような気がします(笑)
スタンダードエディションでも、新しめの(IContextMenu2まで書いてある)
ちゃんと、 Win32SDKヘルプも入ってるし…。
(サンプル類は全く入っていないけど。)
参考資料に、コンパイラ等の付属品がついて、19800円とはお買い得のような
気がする(笑)。
> ほかにこんな不条理な関数はありませんよね?
新しい系統のAPI、時代錯誤な設計のような気がしますね(笑)
きちんと、LPITEMIDLISTの引数をとる用に設計すべきなのに。
作成したビュークラスでOnRButtonClick()を用意して、
その中でデフォルトのOnRButtonDblClk()をコールするか、
自分自身にWM_RBUTTONDBLCLKを送信する、なんて逃げでは
だめでしょうか?
<Q12>に対する回答2
なるほど!その手がありましたか。
でも、MFC標準で出来ないのがしっくりきません...(;_;)
CFrameWnd に対してコンポーネントギャラリから追加するとうまくいくんですが...
<Q12>に対する回答3
Windows 95環境でサービスパック1をあてない状態ではWM_CONTEXTMENUの処理
がおかしいのを個人的に確認しています。右クリックでこのメッセージが送られ
てこず,右ダブルクリックで送られてきます。サービスパック1をあてると右ク
リックで送られてくるようになりました。コンポーネントギャラリーのポップアッ
プメニューはWM_CONTEXTMENUを処理していますから,この辺りの問題ではないで
しょうか。
OnRButtonUpを使うことで解決できますが,これだとコンテキストメニューの起
動が右ボタンで決め打ちになってしまうので,ボタンのアサインを左右逆にして
いる場合に問題が起こりそうです。
<Q12>に対する回答4
サービスパック1は当てて有ります(4.00.950Aでいいんですよね)
当てて有ったはず...。もう一度確認してみます。
現在、手元に確認できる機械が無いので(^_^;)
右クリックでポップアップが開かないのはMFCのせいではないのですね。
implib.exe は MS-C 5.1 〜 7.0 ぐらいまでしかついてなかったような記憶が…。
一応、dumpbin を使えば関数の一覧がでますが、関数の仕様がわかっていれば
LoadLibrary
GetProcAddress
を使って利用することができます。
ボーランドの BC に implib が付いているのは聞いたことあるのですが、VC++
ではインポートライブラリの作成はできないのでは?
<Q13>に対する回答2
VC1.5 には付いてきたのですが,VC4には無いようですね。
インポートライブラリをBooks Online で検索すると
相互インポートという項目で LIB を使うとの記述が
あるのでこれが該当するのではないでしょうか?
> VC++4.2を利用し、当初はコンソールアプリケーションとして作成してみ
> たのですが、うまく動作しなかったため、Windowsアプリケーションにし
> てWM_DESTROYを受け取ったときにExitWindowsExを発行するようにし
> ました。
コンソールアプリかそうでないかでは、本質的な違いはないはずです。
> Windows95上でネットワークにログオンしていないときは、強制
> 的にリブートをすることは可能なのですが、ログオン時は「お待ち
> 下さい」の画面で止まってしまいます。
Windows 95 は普段使用していないのでアレですが、
ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE, 0) を呼び出すだけで良かったよ
うな…。違ったらごめんなさい。
> また、NTの場合はAdjustTokenPrivilegesを使わなければならないと
> ヘルプに書いてあるのですが、発行手順が分かりません。
「Win32 SDK」->「Win32 Programmer's Reference」->「Overviews」->
「System Services」->「Errors」->「Using Errors」に、``Shutting Down''
という項目があり、そこに解説とサンプルが載っています。
『Win32 システムサービスプログラミング』という本がプレンティスホー
ル出版から発売されていますが、そちらにも解説とサンプルがあります。これ
は森下は非常に重宝しており、お奨めの一冊です。
<Q14>に対する回答2
リプライありがとうございます。おかげさまでNTを強制リブートすることが
できました。
なぜかWindows95の方はうまく動かなかったです。コンソールベースで作成する
と、実行時にそのコンソール(DOSプロンプト)のみ終了し、リブートされない
のです。ご紹介の本にも森下さんのいわれる形で載ってますので、当方の環境
が悪いのだと思います。
以下にコード(といってもExitWindowsExを呼んでるだけですが)をのせときま
すので、お気づきの点などありましたらご指摘の方お願いします。
int main(){ ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0); return 0; }
これを実行すると、なぜかリターン値が-1になってるのです。
しかし、GetLastErrorをコールしてもERROR_SUCCESSが返ってきているので、
何が原因か全然分からないんです。どうもすいません。
NTの方はこの本のサンプルをそのまま利用できました。ありがとうございました。
実は、RPCを使ってリモート端末からNTをリブートする仕組みを作ろうとしていた
のですが、NTにローカル・ユーザーがログオンしている場合はリブートできるの
ですが、だれもローカルログオンしていないときはリブートできません。
仕組みとしてはこんな感じなんです。
<Win95> <WinNT4.0>
起動時にNTサービスによりRPCサーバ
プログラムが立ち上がる(Listen状態)
RPCクライアントよりリブートを
行うようメッセージを送信する → リブート・プログラムを実行する
system("c:\MyReboot.exe");
サーバからの返り値表示して終了 ← systeの返り値をコールバック
なぜかリブートしない!
NTサービスのプログラム自体も、system関数でRPCサーバプログラムを立ち上げて
るだけのものです。ちなみに、NTサービスはLocalsystemやAdministorator、プラ
イマリサーバーのAdministoratorのアカウントで実行してみましたが、ログオン・
ダイアログの状態ではRPCの返り値は正常値が返ってくる(RPCサーバは裏で正常に
動作しているということ)のですが、全然リブートされないのです。
原因または解決策をご存知の方がいらっしゃれば、また教えて下さい。
<Q14>に対する回答3
> >> また、NTの場合はAdjustTokenPrivilegesを使わなければならないと
> >> ヘルプに書いてあるのですが、発行手順が分かりません。
"Shutting Down"で探すと,VC++ Books On Lineで見つかります。
> 実は、RPCを使ってリモート端末からNTをリブートする仕組みを作ろうとしていた
> のですが、NTにローカル・ユーザーがログオンしている場合はリブートできるの
> ですが、だれもローカルログオンしていないときはリブートできません。
私は,RPCではなく,WinSockで同じ様な仕組みでサービス・プログラムを書きました。
こちらでは全く問題なく,シャットダウン,リブート出来ていますので,
やはりセキュリティの問題かもしれません。
<Q14>に対する回答4
> なぜかWindows95の方はうまく動かなかったです。コンソールベー
> スで作成すると、実行時にそのコンソール(DOSプロンプト)のみ
> 終了し、リブートされないのです。
以前にコンソールアプリとしてちょっと試して、それでうまく行きました。
ネットワークにログオンもしていましたし…。というわけで、森下は少なくと
も 95 の件に関してはギブアップです。m(__;)m
> 実は、RPCを使ってリモート端末からNTをリブート
> する仕組みを作ろうとしていたのですが、NTにローカル・ユーザー
> がログオンしている場合はリブートできるのですが、だれもローカ
> ルログオンしていないときはリブートできません。
「Win32システムサービス…」のサンプルを使われているとのことなので外
しているかもしれませんが、ひょっとして AdjustTokenPrivileges に失敗し
ていませんか? この API は成功しようがしまいが、必ず ERROR_SUCCESS を返
す、とこの本にはありますし(リスト 10.6)、実際そのようなのですが。
それから、ランタイムライブラリの system 関数のかわりに CreateProcess
を使うとどうなりますか? もしくは作成されたサービスに、「デスクトップと
の対話を許可」するとどうでしょうか? ひょっとして新しいコンソールウィン
ドウをデスクトップ上に開こうとして失敗していたりしないかな、と思ったの
ですが…。こちらも外してたらごめんなさいです。
<Q14>に対する回答5
お返事有り難うございます.先日届いた Microsoft Developer Newsによ
ると,Windows95では ExitWindowEx()を用いてリブートはできないので,
16bit版の ExitWindowを使うように書かれていました.どうもおさがわせ
いたしました.
Win32 ではプロセス空間がそれぞれ独立だからですね--Windows95でも「本
当に」そうなのか、といわれると実はあんまり自信がない--。
VC++ の Online Books の「付録」->「テクニカルリーフ」->「プログラミ
ング」に、``[VC20]前のアプリケーションが起動しているかどうかを調べる方
法''というタイトルで解説と例が載っています。具体的には、同期オブジェク
トであるミューテックスかセマフォを使用します。単一起動にしたい場合には
ミューテックス、複数の起動を許すが数に制限を設けたい場合にはセマフォで
す。
ただし、例では OpenMutex をして既に起動済みかどうか調べていますが、
fj.os.windows.programming で、『OpenMutex に失敗しても、(タイミングの
問題で)厳密には既起動のアプリケーションがすでにあり、そちらも
CreateMutex を行なおうとする可能性がある。よって OpenMutex で判断する
のではなく、いきなり CreateMutex を行なってそれの成功/失敗で判断する方
が良い』という議論があったように記憶しています。その通りかと思いますの
で、CreateMutex で判断する、というのがよろしいかと思います。
蛇足ですが、XXXが初めて Win32 のアプリケーションを書いたときにはこ
の方法ではなく FindWindow 系の API を呼ぶことで判断していました。
<Q15>に対する回答2
> Win32 ではプロセス空間がそれぞれ独立だからですね--Windows95でも「本
>当に」そうなのか、といわれると実はあんまり自信がない--。
一応、アプリケーション固有のコード&データ領域は分離されてます。
> ただし、例では OpenMutex をして既に起動済みかどうか調べていますが、
>fj.os.windows.programming で、『OpenMutex に失敗しても、(タイミングの
>問題で)厳密には既起動のアプリケーションがすでにあり、そちらも
>CreateMutex を行なおうとする可能性がある。よって OpenMutex で判断する
>のではなく、いきなり CreateMutex を行なってそれの成功/失敗で判断する方
>が良い』という議論があったように記憶しています。その通りかと思いますの
>で、CreateMutex で判断する、というのがよろしいかと思います。
そのとおりだと思います。
> 蛇足ですが、森下が初めて Win32 のアプリケーションを書いたときにはこ
>の方法ではなく FindWindow 系の API を呼ぶことで判断していました。
ウィンドウタイトルかクラス名が、ユニークであることが保証されている場合にはそ
れでも ok ですが、MFC を使っている場合には少しばかり苦労することになるので、
Mutex を使う方をお勧めします ;-)
<Q15>に対する回答3
そうですね。当時「テクニカルノート 1:ウィンドウクラスの登録」を読ん
で対処した覚えがあります。当時は残念なことに、同期オブジェクトを使用す
る方法を思いつかなかったのでした。
「共有データセグメントを利用する」という方法も、なるほど、で
すね。pragmma ディレクティブを使用しているので、他の処理系を使う時には
互換性に気をつける必要があるのかな、と思いましたです。
: バージョンとなっており、MSDV統合環境で使用するプロジェクトファイル
: が無いため、ビルドするにもコマンドラインからNMAKEを使用しなければ
: ならないようです。
そんなことないです。新規プロジェクトワークスペースの
タイプをApplicationに指定すれば、ばりばりビルドできます。
: そこで質問ですが、このサンプルプログラムはC言語の仕様で書かれて
: ありまして、これをC++(MFC)に移行する場合はどのようなことを行えば
: よろしいのでしょうか?。また、ターミナルプログラムの様なアプリケーション
: の場合MFCを利用したほうがいいのか、SDKによるほうがいいのか
: 教えてください。
このサンプルをクラス化しましたが、いまのとこ正常に動作してます。
とりあえずアドバイスとしては
StdAfx.hの
// Windows ヘッダーから殆ど使用されないスタッフを除外します。
#define VC_EXTRALEAN
をはずすことかな。
共有する、変数を
#pragma data_seg(".sdata")
......
#pragma data_seg()
でかこんでやったら、後は、defファイルに、
SECTIONS
.sdata READ WRITE SHARED EXECUTE
EXPORTS
以下に変数名を書く
と、データは共有出来るはずです。
後、ファイル マッピングを使うという方法も有りますね。
個人的には、こっちの方がお勧めだと思います。
<Q17>に対する回答2
これを使うのを気づきませんでした。
これで、悩みが解決出来そうです。 ありがとうございました。
<Q17>に対する回答3
リンカオプションでも指定可能です。
ex) -section:.sdata,RWS
<Q17>に対する回答4
DLLの変数の共有について、教えていただいたのですが、どうもうまくいきません。
以下のようなテストプログラムで試してみたのですが・・・
DllTest.C
-----------------------------------------------------
/////////////////////////////////////
// Dll Sample
////////////////////////////////////
#define STRICT
#include <windows.h>
#define DllExport __declspec(dllexport);
#pragma data_seg(".sdata")
int nStockNumber;
#pragma data_seg()
/////////////////////////////////////
DllExport int WINAPI GetNumber( )
{
return nStockNumber;
}
/////////////////////////////////////
DllExport int WINAPI SetNumber( int nNum )
{
nStockNumber = nNum;
return TRUE;
}
-----------------------------------------------------
DllTest.def
-----------------------------------------------------
LIBRARY DLLTEST.DLL
SECTIONS .sdata READ WRITE SHARED EXECUTE
EXPORTS
GetNumber @1
SetNumber @2
-----------------------------------------------------
VC++任せの簡単なDLLプログラムのつもりですが・・・(^^;
なにか、おかしなところがありますでしょうか?
また、#pragma data_segで指定したSECTION名は、DUMPBINでは
見えないのでしょうか? <-テストのDLLでは、”.sdata”は見えませんでした
<Q17>に対する回答5
nStockNumber に初期値を入れてください。
ADVANCED WINDOWS によれば
未初期化変数は .bss セクションに配置されるとのことです。
<Q17>に対する回答6
あっ、そうなんですか・・・φ(。。)メモメモ、っと。
あと、私、Windowsのプログラムをはじめたばかり、というかC言語も・・・
なんですが、その”ADVANCED WINDOWS”というのは?
もしかして、英語の本ですか?
<Q17>に対する回答7
をっと、初期化を見逃していたとは…。
こりゃ、しっけい、しっけい。(^^;)
ADVANCED WINDOWSは、邦訳版も売っていたと思います。
出版社、値段等はわすれました。
<Q17>に対する回答8
.defファイルのEXPORTSセクションに共有するデータも記述しないと
いけないはずです。
DllTest.def
-----------------------------------------------------
LIBRARY DLLTEST.DLL
SECTIONS .sdata READ WRITE SHARED EXECUTE
EXPORTS
GetNumber
SetNumber
nStockNumber
------------------------------------------------------
<Q17>に対する回答9
ADVANCED WINDOWS Jeffrey Richter 著 長尾高弘 訳
ASCII (Microsoft Press) \7,961-
です。
ADVANCED WindowsNT の第2版です。というとみもふたもありませんが
私は、Win16 -> Win32 への移行の際に拡張された機能について
かかれているという認識でいます。
プログラミング Windows 95 の DLL の章にも
同様の記述がありました。
こっちの方が定番でしょうか?
<Q17>に対する回答10
教えてもらった通り、やっと共有化がうまくいきました。
ありがとうございました。 >教えてくださった方々
あっ、日本語版もあるんですか・・・でも 約8、000円かぁ・・・
やっぱり、この手の本って高いですね(^^; > 会社に買ってもらおっと(^^;
素朴な疑問なんですが、SubclassWindow() する必要ってあるのでしょうか?
独自のインプリメントを加えたいのだとして、CLead を派生するのでは不十分なので
しょうか...
<Q18>に対する回答2
当初はCLeadからの派生クラスに各応答関数を実装していたのですが、
実行してみると、応答関数が呼ばれない事が分かったため
サブクラス化を考えたのですが、より良い方法がありましたら
教えて下さい。
VCの場合の処理ですが参考になればと思います。(Win32 APIでの実現方法なので...)
ClipNext = SetClipboardViewer(hWnd);
で、クリップボード ビューアのチェインに、 指定されたウィンドウを追加します。
ClipNextは、クリップボード ビューア チェインの次のウィンドウです。
そうすると、
WM_DRAWCLIPBOARD
WM_CHANGECBCHAIN
がウィンドウに送られてきます。
WM_DRAWCLIPBOARDは、クリップボードの内容が変更されたときに送られてきます。
WM_CHANGECBCHAINは、ウィンドウがチェイン内から削除されるときに送られてき
ます。ClipNextが削除された場合(ClipNext == wParam)は、lParamをClipNextに
設定します。
どちらも、
SendMessage(ClipNext, uMsg, wParam, lParam);
で次のクリップボード ビューアのチェインに送らなければなりません。
(送らないと他のアプリケーションが困ります)
自ウィンドウをクリップボード ビューアのチェインから削除するときは、
ChangeClipboardChain(hWnd,ClipNext);
で削除できます。
OLE、とかゆーのはおいといて(^^;、
memory mapped file とか WM_COPYDATA を使うとかいう手がありますね。
確か、どっちの方法でも、共有memory を媒介して
data を受渡ししているはずですので、
いずれにしても似たりよったりな方法です。
// あとは、地道に WM_USER を使って転送する、とか(^^;。
<Q20>に対する回答2
Win32 ではプロセス空間が分離されているので、単純にメモリブロックを投げつける
という手法は使えません。
が、逃げ道が用意されていて、WM_COPYDATA というメッセージが新設されています。
ヘルプで確認してみてください。
>開発言語が、VC++、BC4.5、SQLWindows(Centura)を同
>時に・・・なもので、出来れば簡単?な方がいいと思いまして(^^;
NT だけがターゲットであれば、名前付きパイプとかが使えて楽なんですが (^^;
<Q20>に対する回答3
方法はいろいろ有ります。
が...
> で、考えたのが下のなんですが・・・
:
略
:
> 7.プログラムBからプログラムAにメッセージをPOST、プログラムA側で
> メモリハンドルを開放する。
ここまで出来てるなら、WM_COPYDATAでする方法が楽でしょう。
この場合、PostMessageではなく、SendMessageを使用してください。
プログラムA
1)メモリのロック
2)SendMessage
3)メモリの開放
みたいな感じでしょうか?
Win32APIリファレンスの、WM_COPYDATA の項目をみてみてください。
<Q20>に対する回答4
ちと横道にそれてごめんなさい。
もともとUNIX屋さんなので、疑問に思ってたのですが、Win32には、Winsockと
いうSocketインタフェースが実装されていますよね?これって、もしかすると、
同一OS上で動作する2つのアプリケーション間では通信することができないん
でしょうか?
<Q20>に対する回答5
できますよ。やろうと思えば、同一アプリケーション内でもサーバ部と
クライアント部がソケットを介して通信する、なんてことも可能です。
話は戻って、プロセス間のデータ受け渡しの方法ですが、文字列程度であれば
Global Atom Tableに登録して渡すというやり方のもあります。
結局 SendMessage()することになるので、WM_COPYDATAと同じなのですが...
<Q20>に対する回答6
Win32 では GlobalAlloc() よりも HeapAlloc() を使用したほうが、少しだけ効率がよいです ;-)
# Win32 は、GlobalAlloc() を HeapAlloc() でエミュレートしているため
<Q20>に対する回答7
>同一OS上で動作する2つのアプリケーション間では通信することができないん
>でしょうか?
もちろんできます。
が、WM_COPYDATA などを使えば、socket の維持などにわずらわされることなく、手軽
に(刹那的に?)ブロックデータの交換が行えますし、プロトコルスタックを必要としません。Windows では、TCP/IP が組み込まれていない場合も想定すべきでしょう。
<Q20>に対する回答8
>ここまで出来てるなら、WM_COPYDATAでする方法が楽でしょう。
>この場合、PostMessageではなく、SendMessageを使用してください。
この一言で、よし!WM_COPYDATA使うぞ(笑)と思いました。
で、会社で、WM_COPYDATAのリファレンスを参照して、
とりあえず、片道だけ動くようになりました。
明日、双方向で動くように頑張ってみたいと思います。
ありがとうございました。
>// あとは、地道に WM_USER を使って転送する、とか(^^;。
これって、自分用のメッセージつくってwParamとlParamに
4バイトずつ、計8バイトを送信しまくるんですか?
そんなのやだなぁ(笑)
<Q20>に対する回答9
># Win32 は、GlobalAlloc() を HeapAlloc() でエミュレートしているため
>
あっ、そうなんですか・・・φ(..)メモメモっと
オーバーヘッドが無くなるぶん効率が良いんですね
つっても、そんなにシビアじゃ無いんですけどね、私のプログラム(笑)
でも、エミュレートしているってことは、やっぱり過去との互換性なんですかね?
したら、そのうちに無くなる可能性も・・・あるのかな?
<Q20>に対する回答10
># Win32 は、GlobalAlloc() を HeapAlloc() でエミュレートしているため
なんか emulate って聞くと、Windows 3.1時代の GlobalAlloc()みたいに
共有memory が確保できるようにも読めてしまいますが、
そんなことはない(あくまで process独立したmemory が確保されうる)ので
注意してくださいね。
こーゆー場合は、stub というのが適切なのかしら?
>>// あとは、地道に WM_USER を使って転送する、とか(^^;。
> これって、自分用のメッセージつくってwParamとlParamに
> 4バイトずつ、計8バイトを送信しまくるんですか?
とーぜんです(^^;。
> そんなのやだなぁ(笑)
しかし、Windows 3.1 に比べると、1.3倍以上の速度飛躍していますし(笑)。
// たんに wParam が 2→4bytes になっただけ(^^;。
<Q20>に対する回答11
> つっても、そんなにシビアじゃ無いんですけどね、私のプログラム(笑)
> でも、エミュレートしているってことは、やっぱり過去との互換性なんですかね
Win16 からの移行をスムースにするためにのみ存在します。
生まれたときから Win32 なプログラムで GlobalAlloc() を使う積極的な理由は、た
ぶんないでしょう。(引数が少ないことくらい? ^^;)
> したら、そのうちに無くなる可能性も・・・あるのかな?
まぁ今更無くなることもないでしょうけど ;-)
<Q20>に対する回答12
>なんか emulate って聞くと、Windows 3.1時代の GlobalAlloc()みたいに
>共有memory が確保できるようにも読めてしまいますが、
んー、ちょっと深読みのような気も... (^^:
>そんなことはない(あくまで process独立したmemory が確保されうる)ので
>注意してくださいね。
そうですね、注意してくださいね++
>こーゆー場合は、stub というのが適切なのかしら?
それも少しずれているかな?
内部的に HeapAlloc() を呼び出す、Win16 互換性維持用 API...って長いなぁ (^^;
>しかし、Windows 3.1 に比べると、1.3倍以上の速度飛躍していますし(笑)。
>// たんに wParam が 2→4bytes になっただけ(^^;。
テキストファイルはCStringをシリアライズしたものではありません。
CStdioFileあたりを使って自前で読み込む必要があります。
CArchiveのメンバにGetFileというCFileを返す関数がありますので、
CStdioFile* TextFile=(CStioFile*)(ar.GetFile());
とでもすればよいと思います。
あとは適当にCStdioFileをいじくってみてください。
[Win95タスクバー常駐型プログラム](記事名)
が参考になると思います。(VisualBasicですが(^^;))
具体的な方法は、Shell_NotifyIcon ってAPIを使っていました。
<Q22>に対する回答2
C++ Builderなら、VCLコンポーネントを使いましょう
Delphian World32(主に国内もの)
http://www.asahi-net.or.jp/~fq2a-ok/delphianworld/delphianworld32.htm
Delphi Super Pageのミラー(海外もの)
http://ring.asahi-net.or.jp/archives/pc/delphi/index.html
たくさんのタスクトレイコンポーネントがあります。
僕は、Yukio Tsujiharaさん作のTrayIcon.lzhを使っています。
この場合普通に WriteProfileString( "Desktop", "TileWallPaper", "1" )
でレジストリに書き込まれます。
<Q23>に対する回答2
偶然にもちょうど同じようなことを考えていたのですぐにでてきました。
こんな感じではないでしょうか。(雑誌の丸写しに近いので正しいかどうかは?)
この後にSystemParametersInfoを実行すると一応変わりました。
LONG lRet;
HKEY hKey;
char *sTile = "1";
lRet = RegOpenKeyEx(HKEY_CURRENT_USER, "Control Panel\\desktop",
0, KEY_READ, &hKey);
if (lRet == ERROR_SUCCESS) {
RegSetValueEx(hKey, "TileWallpaper", 0, REG_SZ, sTile, 1);
RegCloseKey(hKey);
}
ただしこれはCのコードですが...
<Q23>に対する回答3
壁紙の表示方法の切り替えが、レジストリ書き換えしかないかどうかは、
残念ながら知りません。
ただ、
> ちなみにC++ Builderを使用しています。
ということなので、ヘルプでTRegIniFilesをご覧になるといいと思います。
<Q23>に対する回答4
んー、たぶん RegOpenKeyEx() の第4引数には KEY_WRITE ビットも立てないと
RegSetValueEx() が失敗してしまうんではないかと思います。
# ていいながら私も実行してみたわけでないのですが
ウインドウ設定としての色属性を変える方法はしりません(泪)
実際に試したことはないのですが・・・CEditView というより、
CView 全体でできると(ASが)思っている方法を書いてみます。
Viewの派生クラスでOnPrepareDC()をオーバーライドします。
| class CMyEView : public CEditView
| {
|
| virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);
|
| };
中身はこんな感じでコーディングすればいいと思いますが・・・
| void CMyEView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo){
| CEditView::OnPrepareDC(pDC, pInfo);
| if (pInfo != NULL) // pInfo は印刷の時に使用
| return; // 画面表示の時はNULL
| pDC->SetBkColor( 背景色を設定 );
| pDC->SetTextColor( 文字色を設定 );
| }
・・・ただし、最初の1回は何とかして「クライアント領域全体」を
塗りつぶす必要があるような気もする・・・
もっと簡単&確実な方法があるなら、教えてください。> 識者の方々
<Q24>に対する回答2
どこかの窓に WM_CTLCOLOREDIT が送られてくるはずなので、
Edit control と同様にそれに応答してあげればいいと思います。
どの窓かは SPY++ で調べればわかると思います。
たぶん、EditView自体か、そのEditViewを持っている frame だと思います。
// 思いっきりはずしている可能性もあるので、注意してください(^^;。
C++Builderを持っていないので想像なのですが、サンプルでは FileFindp は
WIN32_FIND_DATAで宣言されていませんでしたか?
ポインタの宣言だけだと、構造体の実体がないのですが・・・
<Q25>に対する回答2
FindFirstFileの第2引数をアドレス渡しするならば、構造体の定義は
LPWIN32_FIND_DATA FileFindp;ではなく
WIN32_FIND_DATA FileFindp;でしょう。
構造体の定義で頭にLPがつくのは、ポインタという意味ですから
ポインタを渡す限り、構造体の実体がなくてはプログラムが異常
終了するのではないでしょうか?
<Q25>に対する回答3
次のようになるのではないでしょうか?
WIN32_FIND_DATA FileFind;
// FileFindで使うポインタ
HANDLE FindReturn;
//******************
FindReturn = FindFirstFile(".\\TEST.INI",&FileFind);
FindClose(FindReturn);
// ファイルの存在をチェック
if (FindReturn == INVALID_HANDLE_VALUE){
return false;
}else{
return true;
}
か
LPWIN32_FIND_DATA FileFindp;
HANDLE FindReturn;
FileFindp = new WIN32_FIND_DATA();
FindReturn = FindFirstFile(".\\TEST.INI", FileFindp);
FindClose(FindReturn);
delete FileFindp;
if (FindReturn == INVALID_HANDLE_VALUE){
return false;
}else{
return true;
}
のようになるのではないでしょうか?
余計かも知れませんが勝手に変更してしまいました(^_^;
BCBは持っていませんのでチェックはしていないですので間違いあればすいません。
<Q25>に対する回答4
||> LPWIN32_FIND_DATA FileFindp;
||> // FileFindで使うポインタ
||> HANDLE FindReturn;
||> //******************
||> //FileFindp = new sizeof(LPWIN32_FIND_DATA); //無理
-------------------------------------------------
ここでデータの実体を確保するのに失敗しているせいですね。
LPWIN32_FIND_DATAは“ポインタ型”なので、そのサイズの
メモリを確保しようとしてもだめです。ここでは
FileFindp = new WIN32_FIND_DATA;
で必要な構造体のメモリを確保できると思いますが、
WIN32_FIND_DATA dataFileFind;
***
FindReturn = FindFirstFile(".\\TEST.INI",&dataFileFind);
と、データの実体を定義して、そのアドレスを関数に渡す方が
簡単でしょう。
||> VC++のサンプルをみると
||>
||> FindReturn = FindFirstFile(".\\TEST.INI",&FileFindp);
||> ~
||> アドレス渡し?
||> とかかれているのですが同じようにするとエラーでます。
-------------------------------------------------
これも同じで、「アドレス渡し」をしているのは、変数が
“ポインタ型”ではなく、構造体の実体で用意されているためです。
||> 正しい記述又はファイルの存在を確認する他の方法があればお教えください。
-------------------------------------------------
ちなみに、ASはVC++を使用していますが、ファイルの存在確認は
CFileクラスの静的関数(オブジェクトを作らなくても利用できるヤツ)
のCFile::GetStatus()をよく利用します。BCBのファイルアクセス関連
クラスには、「ファイルの状態を取得」って関数はありませんか?
CFile::GetStatus()だと返値が論理値で、ファイルが存在すれば
TRUE、見つからなければFALSEを返すので手っ取り早いですよ。
<Q25>に対する回答5
いろいろと勘違いしてたみたですね..>自分
FindFirstFileが勝手ににメモリ割り当てしてくれるとか
LPWIN32とWIN32の違いはBCBとVC++の違いとか...
勝手に間違って解釈していました。
OS を Windows NT に変えればいいはずです(^^;。
Windows 95 で、edit-control を使う限り、
64KB の壁は越えられなかったと思います。
MFCでしたらCreateFontで任意のフォントがつくれます。
<Q27>に対する回答2
1.CreateFontで任意のフォントを作成する
2.DCに対してフォントオブジェクトを選択する。
3.TextOut等の描画。
4.フォントを選択前に戻す。
の手順で角度付きの文字を表示する事ができます。
CreateFontは重い処理です。
CAD系のアプリでしたら描画速度が命ですので、
同じフォントのものであれば連続して描画させる、
文字列に外接する矩形を描画するモードと
本当に文字列を描画するモードに分けるなどの工夫が
必要かと思います。
void CSampleView::OnDraw(CDC* pDC)
{
CGomiDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CFont* pOldFont;
CFont NewFont;
NewFont.CreateFont( 0,//int nHeight,
0,//int nWidth,
450,//int nEscapement,
0,//int nOrientation,
FW_NORMAL,//int nWeight,
0,//BYTE bItalic,
0,//BYTE bUnderline,
0,//BYTE cStrikeOut,
DEFAULT_CHARSET,//BYTE nCharSet,
OUT_DEFAULT_PRECIS,//BYTE nOutPrecision,
CLIP_DEFAULT_PRECIS,//BYTE nClipPrecision,
DEFAULT_QUALITY,//BYTE nQuality,
DEFAULT_PITCH,//BYTE nPitchAndFamily,
"MS 明朝");//LPCTSTR lpszFacename
pOldFont = pDC->SelectObject( &NewFont );
pDC->TextOut( 100, 100, "こんな感じでどうでしょう。");
pDC->SelectObject( pOldFont );
}
≫でコンパイルした場合は、Win95/NTのいずれでも起こりません。ただし、NT&
≫VC++4.2でも、環境変数TZ=JST-9と設定しておけば正しく動作します。
私が使用しているのはVC++4.1ですが以前同様の症状が起きたのでランタイム
ライブラリのソースを追っかけてみると、_tzset内で使われている
GetTimeZoneInformationがNTと95で異なる値を返していることが原因でした。
≫ さて、そこで質問なんですが、これってVisualC++4.2のバグなのでし
≫ょうか?。
Win32 APIという方が正しいのかな?
≫MSのKnowledge Baseには該当する項目はないみたいなのですが、私にはどう見
≫てもライブラリのバグとしか思えません。
以下のVCのサポート技術情報にタイムゾーンに関する報告があります。
http://www.microsoft.co.jp/support/tdoc/doc/c/CPJ6388.htm
<Q28>に対する回答2
>以下のVCのサポート技術情報にタイムゾーンに関する報告があります。
>http://www.microsoft.co.jp/support/tdoc/doc/c/CPJ6388.htm
この件については、今年の2月頃にマイクロソフトのサポートに問い合わせた
ことがあります。やはり(APIではなく)ライブラリのバグとのことでした。
たしかにライブラリのコードを見てみるとGetTimeZoneInformation()の
チェックの仕方に誤りがあることが分かります。
で、これについては「VC++5.0で修正される予定です」という答えを
もらいました(「リリース予定は?」の問いには「不明」との答えでした^^;)
現状での対処方法は「TZ環境変数を設定する」というものです。
上記のサポート技術情報ページでは日本時間を前提とした対処法が
載っていますが、これではあんまりですね。
かといって、すべてのユーザにTZ環境変数を設定してもらうというわけ
にも・・・。
しょうがないので、プログラムの最初に以下のような方法で無理矢理
_timezoneを更新しています。
TIME_ZONE_INFORMATION tzinfo;
DWORD res = ::GetTimeZoneInformation( &tzinfo );
_timezone = tzinfo.Bias * 60L;
_daylight = 0;
こうすればなんとなく動いています。サマータイムを正しく扱えない
という欠点がありますが。
<Q28>に対する回答3
なるほど、Win32 APIの問題でしたか。しかし・・・WinAPIって、実質はWindows
内のDLLそのものだと聞いたことがあったのですが、するとなんでVC++4.0では動いた
んでしょうね。うーん、GetTimeZoneInformationは単なるDLL呼び出しではなかった
という事でしょうか。
>以下のVCのサポート技術情報にタイムゾーンに関する報告があります。
>http://www.microsoft.co.jp/support/tdoc/doc/c/CPJ6388.htm
なるほど、美事に「環境変数を設定しとけ」と出てますね。さすがはマイクロ
ソフト、バグ報告も回避策の伝授も、まるで当然のことを説明するがごとく堂々
としてますね。
>この件については、今年の2月頃にマイクロソフトのサポートに問い合わせた
>ことがあります。やはり(APIではなく)ライブラリのバグとのことでした。
>たしかにライブラリのコードを見てみるとGetTimeZoneInformation()の
>チェックの仕方に誤りがあることが分かります。
ああ、つまりAPIそのものではなく、呼び出し方とか戻り値の利用とかに問題
があるというわけでしょうか。いずれにしても、マイクロソフトがちゃんと
「ライブラリのバグ」と言いきってるなら安心です。だって上役への説明で
私の責任とは言えなくなりますから(^_^;)。
>で、これについては「VC++5.0で修正される予定です」という答えを
>もらいました(「リリース予定は?」の問いには「不明」との答えでした^^;)
>現状での対処方法は「TZ環境変数を設定する」というものです。
うーん、開発環境に堂々とバグ入れといて、ものすごい態度してますよね。
>上記のサポート技術情報ページでは日本時間を前提とした対処法が
>載っていますが、これではあんまりですね。
>かといって、すべてのユーザにTZ環境変数を設定してもらうというわけ
>にも・・・。
>しょうがないので、プログラムの最初に以下のような方法で無理矢理
>_timezoneを更新しています。
> TIME_ZONE_INFORMATION tzinfo;
> DWORD res = ::GetTimeZoneInformation( &tzinfo );
> _timezone = tzinfo.Bias * 60L;
> _daylight = 0;
なるほど、システムの設定値を自前で取ってきて設定するわけですか。
うーん、かっこいい。
>こうすればなんとなく動いています。サマータイムを正しく扱えない
>という欠点がありますが。
とりあえず私は、一度時刻を(絶対秒で)手に入れたあと、localtime
を通して夏時間が有効かどうかをチェックして、1時間のずれをいれるか
どうか判断するようにしました。・・・・・まあどうせ日本国内でしか
使わないので、TZ=JST-9を強制設定するだけで問題ないんですけど、その
へんは偏屈ぷろぐらまのコダワリってもんで(^_^;)
とにかくおかげで助かりました。どうもありがとうございました。
<Q28>に対する回答4
> なるほど、Win32 APIの問題でしたか。しかし・・・WinAPIって、実質はWindows
>内のDLLそのものだと聞いたことがあったのですが、するとなんでVC++4.0では動いた
WINAPI の多くは DLL内にあると思います。
>んでしょうね。うーん、GetTimeZoneInformationは単なるDLL呼び出しではなかった
>という事でしょうか。
「単なる」というのが、微妙な言葉でよくわかんないですけれど、
DLL っつーても、自分で作ったふつーの DLL とは格が違うと思います。
特権水準とか。一部、RING0 で動いていますよね。
DLL って、拡張子が .dll のものをさすのではなくて、
dynamic linkage する library が DLL なのですから、
考えようによっては、MS-DOS の DOS function call(int 21h)なんていうのも
DLL呼びだしに含み得ますよね(ちょっと苦しいかな?)。
>>現状での対処方法は「TZ環境変数を設定する」というものです。
> うーん、開発環境に堂々とバグ入れといて、ものすごい態度してますよね。
ふつー TZ を設定するでしょう、って、そうでもないか(^^;。
>>上記のサポート技術情報ページでは日本時間を前提とした対処法が
>>載っていますが、これではあんまりですね。
>>かといって、すべてのユーザにTZ環境変数を設定してもらうというわけ
>>にも・・・。
自分のprogram内だけの対応でよければ、
実行開始早々に自分で設定してしまうという手もありますね。
といっても、
>>しょうがないので、プログラムの最初に以下のような方法で無理矢理
>>_timezoneを更新しています。
とおなじようなものか。
<Q28>に対する回答5
ガチョーーン、タイムゾーンAPIにバグがあるなんて。!!
今の話題ってMSのインターネットメールがまさにその症状なんです。
これでわかりました、そもそも作ってるところのAPIがHOGEテっるんですね?
MSインターネットメールでの文字コード化けのバグも充分推測されます。
私は、今、インターネットFAXという製品を開発しているので
メーラは各種、使ってテストしていますが、
MSの日本語インターネットメールにはいつも悩まされています。
しかし、これでMSは平気な顔をしているのでしょうか?
<Q28>に対する回答6
あのぉ、NTのAPIにバグがあるというよりも、
VC++4.2の標準ライブラリの実装にバグがある、
ということらしいです。
MSの説明によるとVC++4.1では問題ないそうです(確かめては
いないけど)。ライブラリに頼らないで直接APIを使えば、
とりあえず対処できるみたいです。
OWLには確かTDIBというクラスがあったと思います。
ファイルから直接読み込むメソッドも画面に書くメソッドもあったはず。
TDib myDib;
TMemoryDC myMemDC;
TClientDC dc;
myDib.LoadFromFile("Hoge.bmp");
myMemDC.Draw(myDib);
dc.BitBlt(myMemDC, 0, 0, myMemDC.Width(), myMemDC.Height());
みたいなことをやるのでは?
(OWLは忘れてしまったのでコードはアルゴリズムを表している
程度に思ってください)
>> TC++に対応しているものは見かけません。
>> 何かいい本がありましたら紹介して下さい。
OWLということならTCじゃなくてBC++の本が参考に
なるのでわ?と思います。
<Q29>に対する回答2
> ファイルから直接読み込むメソッドも画面に書くメソッドもあったはず。
ということで、そのコードを(実際とは少々違いますが)
変数
TOpenSaveDialog::TData *FileData;
プログラム
TDib myDib(FileData->FileName);
TClientDC dc(*this);
TMemoryDC myMemDC;
TBitmap myBit(dc, myDib);
myMemDC.SelectObject(myBit);
int h = myBit.Height(), w = myBit.Width();
dc.BitBlt(0, 0, w, h, myMemDC, 0, 0);
myMemDC.RestoreObjects();
です。
始めの自分のソースと異なるのは TClientDC を使うかどうか、ですね。
マニュアルには TDC とあり、一体何者だかわからなったかものですから、
これがあちこちのコンストラクタに出てくるため、これらを使えませんでした。
単純に自分の this を使って作った TClientDC のインスタンスで良かったのですね。
> >> TC++に対応しているものは見かけません。
> >> 何かいい本がありましたら紹介して下さい。
> OWLということならTCじゃなくてBC++の本が参考に
> なるのでわ?と思います。
というわけで、引き続きTC++およびBC++の
Windowsに関する書籍を探しています。
<Q29>に対する回答3
http://www.borland.co.jp/
ボーランド製品関連書籍情報っていうのが載っています。
でも、ほとんどDelphiだったと思います。Turbo C++で
載っていた本も、すごく古いヤツのような気がします。
Borland C++Builderならこれからたくさん出てくる
みたいですけど・・・。
Last Update
1998/03/23