VC6とVC9の違い

[戻る]
まなみ 2010/04/05(月) 14:44:31
いつもお世話になります。

EXE(VC6)とDLL(VC6)の構成にて、VC6ではDLLにてAfxGetApp()を行っても
正常な値が返ります。
EXE(VC9)とDLL(VC6)の構成では、NULLが返ってきます。

これは、コンパイラの問題でしょうか?
VC6同士ではたまたま動いたということでしょうか?

DLL(VC6)にてAfxGetApp()など使わないように変更することは、不可能な
話ではないのですが、DLLを変更せず、上位EXE(VC9)側の変更にて対応
することは可能でしょうか?

わかる方いらっしゃいましたら、ご教授願います。

maru 2010/04/05(月) 16:28:35
質問がよくわかりません。
AfxGetApp()はアプリケーションにただ 1つしかないCWinAppオブジェクトへのポイ
ンタを返しますが、MFCで作成した場合、CWinAppオブジェクトはExeとDLLの両方に
存在して、其々でそのポインタを返します。つまり、ExeのAfxGetApp()とDLLの
AfxGetApp()は別のものを指すわけです。

> EXE(VC9)とDLL(VC6)の構成では、NULLが返ってきます。
とはどういう状況をいっておられるのでしょうか?
EXE(VC9)側でNULLが返ってくるのであれば、DLLとは無関係の問題と思われます。

仲澤@失業者 2010/04/05(月) 16:59:12
自分は実際には遭遇したことはありませんが、
関係ありそうな情報は以下のものです。

MFCで呼び出し側の状態(モジュール状態)を使用するには、
AFX_MANAGE_STATEマクロを使う必要があります。

・MFC と動的にリンクされるレギュラー DLL のモジュール状態
・MFC モジュールの状態データの管理
・テクニカルノート58:
・http://support.microsoft.com/kb/140850/ja

等を参考にして、DLL側を変更する必要があるかもしれません。

ただ、これらの方法は「DLL側」の変更になるため、
>DLL(VC6)にてAfxGetApp()など使わないように変更することは、不可能な
>話ではないのですが、(引用者が省略)
であれば、そのように変更したほうが良い場合もありえます。

仲澤@失業者 2010/04/05(月) 17:08:06
おっと、かぶったので、やや補足(^^;)。

MFC4.x(だったかな)のころは、DLL側でAfxGetAPP()しても呼び出し側
のCWinAppが取得できていたのです。
その頃のソースではないかと推測できます。

maru 2010/04/05(月) 18:52:49
> MFC4.x(だったかな)のころは、DLL側でAfxGetAPP()しても呼び出し側
> のCWinAppが取得できていたのです。
なるほど、そんな時代があったんですね。

http://msdn.microsoft.com/ja-jp/library/3z02ch3k(v=VS.90).aspx
によれば、MFC4.0はVC++4.0の頃。たしか、その頃はWIN32 APIでコードを書いて
いたような気がする。だから、そんな知識がありませんでした。

もしそうだとすると、DLL側も直す必要がありますね。

でも、これ
> EXE(VC6)とDLL(VC6)の構成にて、VC6ではDLLにてAfxGetApp()を行っても
> 正常な値が返ります。
はDLL側でAfxGetApp()をやって、EXE側のCWinAppを取得できたってことですよね。
ほんとにそんなことできるんだろうか?

ってことで実験をしてみました。
VC6のDLLでDLL側のCWinAppのインスタンスが存在しない状態でAfxGetApp()を呼び出し
て見ましたが、0が返ってきて、Exe側のCWinAppなんて取得できませんでした。
> 正常な値が返ります。
とは、どういうことでしょうかね?

仲澤@失業者 2010/04/05(月) 19:06:26
>ってことで実験をしてみました。
>VC6のDLLでDLL側のCWinAppのインスタンスが存在しない状態でAfxGetApp()を呼び出し
>て見ましたが、0が返ってきて、Exe側のCWinAppなんて取得できませんでした。
>> 正常な値が返ります。
>とは、どういうことでしょうかね?

だと、思います(vv;)。
そこはスレ主さんに、何か勘違いがあるのではないかと思いましたが、
maruさんが、既に指摘済みなので・・・OKっと。

まなみ 2010/04/06(火) 08:53:39
皆さん、いろいろとありがとうございます。

私もダイアログベースでテストプログラムも作成して再度確認してみました。
1.VC6でDLLを作成
 この中でAfxGetApp()をコールする
2.VC6とVC9でEXEを作成
 DLLの関数をコールする(LoadLibraryとGetProcAddress)

結果、
VC6(EXE)とVC6(DLL)では、
(EXE)OnInitDialogでAfxGetApp()-->0x004167a0
(DLL)呼ばれた関数でAfxGetApp()-->0x004167a0

VC9(EXE)とVC6(DLL)では、
(EXE)OnInitDialogでAfxGetApp()-->0x00af7310
(DLL)呼ばれた関数でAfxGetApp()-->0x00000000
となりました。

皆さんの言っていることと矛盾しているようですが、実際できています。
よくわかんなくなってきました。
 

bun 2010/04/06(火) 09:23:34
DLL側がデバッグできると言うことはソースコードは持ってるんですよね?

だとすると、簡単にできそうな話で1つ抜けている気がするのですが、
VC6のDLLをVC9でビルドし直した上で、
  EXE(VC9) → DLL(VC9)
はどうでしょうか?

あと、DLLにもいろんな種類があります。

> VC6(EXE)とVC6(DLL)では、
> (EXE)OnInitDialogでAfxGetApp()-->0x004167a0
> (DLL)呼ばれた関数でAfxGetApp()-->0x004167a0
同じアドレスを返すと言うことは、MFCの拡張DLLですか?

拡張DLLの場合、クラスごとエクスポートしますので、
EXEとDLLのMFCは同じ物(バージョン)でないとまずい気がします。

たいちう 2010/04/06(火) 09:26:22
> 皆さんの言っていることと矛盾しているようですが、実際できています。

VC6がないから実験できませんが、取得できたとしてもCWinAppの定義が
VC6とVC9とでは変わってませんか?VC9のCWinAppへのポインタを
VC6のCWinAppへのポインタとみなして処理するんでしょ?
成功したとしても、それこそたまたま動いているとしか評価できないのですが。

まなみ 2010/04/06(火) 09:34:49
> DLL側がデバッグできると言うことはソースコードは持ってるんですよね?
いえいえ、テスト用に作って試しているだけです。

で、EXE(VC9) → DLL(VC9)をテストしてみました。

(EXE)OnInitDialogでAfxGetApp()-->0x008f7310
(DLL)呼ばれた関数でAfxGetApp()-->0x008f7310
と問題ありませんでした。

bun様と言う通り、拡張DLLを使用していますので、そこが問題と
言うことでしょうか?

これから、拡張DLLでないタイプで試してみます。

たいちう 2010/04/06(火) 09:53:13
VC6で作ったexeとdllがあって、どっちもVC9にバージョンアップさせたいけど、
dllのソースコードはない、という状況ですか?
dll側では、exeのCWinApp*を取得して、何に使っているのかわかりますか?

まなみ 2010/04/06(火) 10:18:25
MFCの共有DLLを使用で行ってみました。
(EXE)OnInitDialogでAfxGetApp()-->0x00307310
(DLL)呼ばれた関数でAfxGetApp()-->0x00000000
結果、とれませんでした。

> VC6で作ったexeとdllがあって、どっちもVC9にバージョンアップさせたいけど、
> dllのソースコードはない、という状況ですか?

もともと、EXE(弊社)、DLL(他社)にてVC6で作成していました。
そして、双方ともVC9へバージョンアップを計画していましたが、
DLLができない状態にあり、VC9(EXE)とVC6(DLL)の組み合わせでテストしています。

> dll側では、exeのCWinApp*を取得して、何に使っているのかわかりますか?

AfxGetApp()->GetProfileInt()やCWaitCursorなど、他にもありそうです。
他社にAfxGetApp()を使用している箇所を修正してもらうことは可能だと
思われますが、全ての項目を再チェックしなければならなく、上位(EXE)側の修正
のみで行えないものかと思っています。

たいちう 2010/04/06(火) 11:02:24
dllをVC9に変更することはできないけど、VC6のまま若干の修正なら可能ということですか?
例えば、古いハードの制御のために、dllはVC6で作らざるを得ない、
というような事情があれば、ソースコードがあっても仕方ないですね。

dllを変更してしまうとdll側のテストもやり直しになりますが、
無理してexeだけの変更で対応させることに成功したとしても、
無理した分、それなりのテストが必要ですし、何より怖いのが、
Windows Update等で動かなくなる可能性が付きまとうことです。
VCのバージョンに依存しない形にdllも変更してもらうしかないと思いますが。
コストとリスクを評価してみてください。

# VC9のCWinAppのインスタンスをVC6のCWinAppとして使用することについて、
# 何の保証もない、という私の認識が正しかった場合の話です。
# 保証されているという記述をMSDNなどで見つけることができれば
# 全く問題ないですし、「この方法で取得できるよ、経験的に問題ないよ」
# という方がいれば、選択肢が増えますが。

まなみ 2010/04/06(火) 11:41:05
たいちう様、回答ありがとうございます。

私が開発する範囲なら、面倒でもなんとかなるかと思います。
冒頭の質問のようにEXE側のみで対応が可能であるか否かを知りたいのです。
DLL側を修正すれば、対応可能であることは周知のことです。
そんな方法はないと言われれば、それまでですが。。。。

たいちう 2010/04/06(火) 13:06:21
腕に自信があって面倒でも構わないならば、
CWinAppのダミーのインスタンスを持つexeをVC6で作り、
VC6のdllはこのexe経由で呼出し、
VC9のexeでこのインスタンスを更新・監視しておくとか、
バージョンの違いを吸収するdllをVC6で作ってラッパーにするとか、
元のdllに手を触れないで済ませる方法はあるでしょう。
よほどの事がない限り私はこんな選択はしませんが。

お望みの回答でなくて申し訳ないですが、私に言えるのはここまでです。
良い方法が見つかるといいですね。

2010/04/06(火) 13:07:33
互換性ない
一方はMFC4.dllで別のdllだからMFCオブジェクト渡すと危険
携帯なので以下略

bun 2010/04/06(火) 13:25:55
VC6 と それ以降のバージョンへの過渡期によくある問題ですね。
手っ取り早いのは、過渡期を過ぎるまでVC6, VC9のどちらでもビルド可能な
ソースコードにしてしまうことです。

注意深くやれば、ほとんどのソースコードは共有可能です。
どうにも互換性のない部分だけ、以下の#ifで処理分けします。

#if _MSC_VER > 1200    // VC9
#else                  // VC6
#endif

DLL側がVC9に対応するまでは、VC6でビルドして、
DLL側がVC9に対応したら、VC9でビルドし直す。

私の場合、そんな方法で対処した記憶があります。

maru 2010/04/06(火) 13:27:33
> 皆さんの言っていることと矛盾しているようですが、実際できています。
確かに bun さんがおっ社ているように拡張DLLだと DLL 側からAfxGetApp()で
アプリ側の CWinApp* が取れるようですね。
でもVC6とVC9ではCWinApp自身が同じではないので非常に危険です。
(と言うより、互換性がないのでやっちゃいけないのでは...)

つまりExe側でなんとか出来るような問題ではないでしょう。
> 一方はMFC4.dllで別のdllだからMFCオブジェクト渡すと危険
この一語に尽きる。

まなみ 2010/04/06(火) 13:38:28
皆さん、ありがとうございます。

結局、そう簡単にはできないみたいですね。
簡単と言うより無理に等しいと判断した方がよさそうですね。

因みになんですが、maru様も試されたみたいですが、
拡張DLLでAfxGetApp()の使用は、どうなんでしょうか?
本来あってはならないもの、それとも結果OKのもの??

今後、DLLを作成する場合のノウハウとして。

bun 2010/04/06(火) 14:06:23
> 拡張DLLでAfxGetApp()の使用は、どうなんでしょうか?
> 本来あってはならないもの、それとも結果OKのもの??

EXE と DLL の MFCのバージョンが同じなら当然あり。
違うなら当然あってはならない。

だと思う。

ryo 2010/04/06(火) 14:16:30
http://msdn.microsoft.com/ja-jp/library/h5f7ck28.aspx
より

クライアント アプリケーションおよび拡張 DLL の両方で、同じバージョンの 
MFCx0.dll を使用する必要があります。

maru 2010/04/06(火) 14:18:34
> 拡張DLLでAfxGetApp()の使用は、どうなんでしょうか?
> 本来あってはならないもの、それとも結果OKのもの??
以下に全ての回答がありました。
http://msdn.microsoft.com/ja-jp/library/h5f7ck28(v=VS.80).aspx
「拡張 DLL では、CWinApp の派生クラスをインスタンス化はしないでください。その代
わりに、このオブジェクトの提供をクライアント アプリケーション (または DLL) に依
存します。」
つまり拡張DLLは正しい方法、それ以外ではNG。

また、MFCのバージョンの話も
「クライアント アプリケーションおよび拡張 DLL の両方で、同じバージョンの 
MFCx0.dll を使用する必要があります。」
とあります。

maru 2010/04/06(火) 14:22:24
ありゃ、かぶっちゃいましたね。 

ちょっと修正。
> つまり拡張DLLは正しい方法、それ以外ではNG。
つまり拡張DLL「で」は正しい方法、それ以外ではNG。

まなみ 2010/04/06(火) 15:55:29
[[解決]]
> つまり拡張DLL「で」は正しい方法、それ以外ではNG

なるほど。わかりました。
ありがとうございます。

VCのバージョンアップの度にこのような問題がでてくるのであれば
拡張DLLを使用しない方がよさそうですね。
勉強になりました。

bun 2010/04/06(火) 16:10:42
私の場合は、MFCの拡張DLLは、1つのソリューション(ワークスペース)にEXEとDLL
双方のプロジェクトを含める場合にだけ使うようにしています。

常に同時にビルドがかかる状態なら、バージョンの不一致問題は起きないわけで、
そうなるとデメリットよりメリットが勝るからです(^-^)

古いスレッドには追加発言できません。