開発環境は VB6SP6+WinXPSP2です。
自作のソフトを不特定多数の人に実行ファイルだけ公開する場合、開発者は必要なDLLやOCXファイルが何かはあらかじめ分かりますが、ユーザーのほうでは自分のパソコンがそれを満たしているかどうかは分かりにくいかと思います。
そこで、必要なシステムファイルが使用可能かどうかを調べてデバッグログに書き出すコードを追加することを考えています。
Public Sub CheckSysFiles()
Dim SysFile(20) As String
Dim SysPath As String
Dim i As Long
Dim Ret As String
SysFile(0) = "GDI32.dll"
SysFile(1) = "user32.dll"
SysFile(2) = "olepro32.dll"
SysFile(3) = "gdiplus.dll"
SysFile(4) = "ole32.dll"
SysFile(5) = "kernel32.dll"
SysFile(6) = "winmm.dll"
SysFile(7) = "shlwapi.dll"
SysFile(8) = "comdlg32.dll"
SysFile(9) = "shell32.dll"
'
SysFile(10) = "msvbvm60.dll"
SysFile(11) = "OLEAUT32.dll"
SysFile(12) = "ASYCFILT.dll"
SysFile(13) = "COMCAT.dll"
SysFile(14) = "VB6JP.dll"
SysFile(15) = "scrrun.dll"
SysFile(16) = "dx8vb.dll"
SysFile(17) = "comdlg32.ocx"
SysFile(18) = "MSCOMCTL.ocx"
'
SysFile(19) = "VB6.OLB"
SysFile(20) = "STDOLE2.TLB"
SysPath = Environ("WINDIR") & "\system32\"
For i = 0 To 20
Ret = Dir(SysPath & SysFile(i), vbSystem)
If Len(Ret) = 0 Then
' 自作ログ書出プロシージャ
Call DebugOutput("System File of " & SysFile(i) & " is Not Find")
End If
Next
End Sub
例えば上記のようなコードだと、パスが通ったところに置けばいいような普通のシステムファイル(?)なら問題ないのですが、COM/ActiveXのシステムファイルのようにレジストリに登録されていなければならないファイルの場合では片手落ちだと思っています。
DLLファイルを SYSTEM32 フォルダに放りこんでレジストリに登録しない人もいるかもしれません。
また、gdiplus.dllなどは、インストールされているフォルダが良く分からない場所になっています(system32にはいない)。
上記のコードの場合、SysFile(0)〜SysFile(9)のファイルは必ずWindowsに入っているというならばチェックは不要かと思います。
と、いうことで、
「自作ソフトの実行に必要なファイルが使用可能かどうか調べるにはどのような方法があるのでしょうか?」
COM/ActiveXのDLL&OCXファイルだけなら、例えば VerFindFile関数 でパスが返るかどうかでチェックする方法もありかな、と思ってますが、どんな方法がいいですかね。
仕様の話はVBとは関係ないですね。
チェックするという考えは、実は面白いところだったりします。
その上で、
まず、0〜2、4〜6、8、9は、OSに備わっているDLLと考えられます。
これらは存在チェックをする必要がありません。なければそもそも
動かないでしょう。
また、7も、特定のOS以降には備わっているDLLですので、同様と
考えられます。
3のGDI+のエンジンですが、これも最近のOSでは備わっているとも
言えますが、実のところ特定のディレクトリ(System32など)に配置
されている必要はありません。また、Microsoftから単独で取得できる
ようになっていたと思います。
10は...そもそもこれがないとVBのコードが動きませんよね?
同様に、VB系のDLLとして11〜14、17〜19が列挙できます。
但し17、18は必ずしも必須ではありません。20はDLLではありません。
まぁ、OSの種類も不定ですから、もしチェックするにしても。
3、7、14〜19の存在チェックをするだけでいいでしょう。
で、DLLの存在チェックで簡単なのは、API関数のLoadLibraryと
FreeLibraryを組み合わせて使うことだと思います。
最終目的地を書いておいたほうがいいかと思ったんですけど、別にいらないようですね。
以後気をつけますね。
LoadLibraryを調べたところ丁度よさそうです。
ただ、規定の場所以外でレジストリに登録されていた場合はどうなるんでしょうか?
App.PATHと、windowsフォルダ、systemフォルダ、環境変数のフォルダだけだと含まれ無いような気がしますが。
いまいち自分で確認するのが難しいのですけど仕様上はいかがなものでしょう?
17、18はこのコントロール使っているので組み込もうとしているソフトでは必須かと思ってます。
上記コードでDIR付近を置き換えて確認してたら19だけがヒットしませんでした。(20は放置しました)
.OLBファイルはタイプライブラリ付きのDLLだとどこぞで書いてありましたが、LoadLibraryできないのは仕様でしょうか、勘違いでしょうか?
19のVB6.OLBもDLLではありませんのでチェックは不要でしょう。
19を入れて書いていたのは私のミスですので、訂正してください。
なお、タイプライブラリですが標準のフォーマットではありません。
で、レジストリに登録してあることを利用するのであれば、そこから調べる、という手がありますよね。
例えば19は、
HKEY_CLASSES_ROOT\TypeLib\{FCFB3D2E-A0FA-1068-A738-08002B3371B5}\6.0\?\win32
で調べる、という存在チェックはできます。まぁ19はそもそも実行時には
なくても大丈夫だったと思います。
# ?のところは0〜9のどれかだったと思います。特定できないケースがあります。
15〜18は、COMオブジェクトを提供するDLLですが、それぞれタイプ
ライブラリを含むので、バージョンが下記のものでいいのならば、
15:
HKEY_CLASSES_ROOT\TypeLib\{420B2830-E718-11CF-893D-00A0C9054228}\1.0\0\win32
16:
HKEY_CLASSES_ROOT\TypeLib\{E1211242-8E94-11D1-8808-00C04FC2C603}\1.0\0\win32
17:
HKEY_CLASSES_ROOT\TypeLib\{F9043C88-F6F2-101A-A3C9-08002B2F49FB}\1.2\0\win32
18:
HKEY_CLASSES_ROOT\TypeLib\{831FDD16-0C5C-11D2-A9FC-0000F8754DA1}\2.0\0\win32
を調べることになるのでは。
まぁ、バージョンやその次の番号は特定できるとは限らないので、列挙してみる
方がいいかも知れません。
あ、解決にするの忘れてました。
解決・・・かと思ったのですが、
開発環境の入っていないパソコンでは、VB6JP.dllが見つからないことが分かりました。
でも、動作には問題無いようです。ということは無くてもOKと言うことでしょうか?
もともとこのファイルを入れていたのは、ディストリビューションウィザードがインストーラーを作成しようとした際に、組み込もうとしていたシステムファイルに含まれていたからなのですが・・・
あるEXEファイルの実行に必要なシステムファイルをピックアップするいい手段は無いものでしょうか?
> VB6JP.dllが見つからないことが分かりました。
日本語リソースのサテライトDLLです。
無くても動く事は動きますが、VB6JP.DLL が無い場合、
既定のフォントが欧文フォントに変化したり(文字化けの原因)、
エラーメッセージ等が英語で表示される事になりますよ。
> あるEXEファイルの実行に必要なシステムファイルをピックアップするいい手段は無いものでしょうか?
Visual Studio Installer / ディストリビューション ウィザード等に
任せておけば良いのでは?
>あるEXEファイルの実行に必要なシステムファイルをピックアップするいい手段は無いものでしょうか?
実行中のプログラムなら
WindowsXPなら
tasklist /M
でしょうか。
自作ソフトの配布はEXEファイル単体ということを前提で考えています。
不特定多数の実行環境で必要なDLL、OCXファイルがそろっているかどうかをチェックしたいのが骨子です。
そこで、ディストリビューションウィザードがこの自作ソフトのインストーラーを作成する際に収集されるファイルと、使用しているAPI関数が収まっているDLLファイルが、実行環境に揃っていればよかろう、と考えました。
tasklist /m はこれはこれでかなり面白いのですが、間接呼び出しもリストアップされているようなので、ちょっとちがうなぁという感じです。
結局、単体配布のときはVBランタイム周りのDLL&OCXファイルが不足するのであろうということから、
参照設定しているDLL&OCXを、都度手作業でリストアップするべきなのかなと思います。
加えて、ついでにAPI呼び出し先のDLLファイルもチェックしたほうがいいのかな、と。
ということで、手作業でリストアップしたDLL&OCXファイルをLoadLibraryできるかどうかでチェックすることにしました。
とりあえずこれで解決とします。
どうもありがとうございました。
'┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
'┃ 名称 :CheckSysFiles
'┃ 説明 :使用しているAPI、コンポーネントに必要なシステムファイルがあるかどうか検索する
'┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Public Sub CheckSysFiles()
Dim SysFile(18) As String
Dim i As Long
Dim Ret As String
Dim hdl As Long
SysFile(0) = "GDI32.dll"
SysFile(1) = "user32.dll"
SysFile(2) = "olepro32.dll"
SysFile(3) = "gdiplus.dll"
SysFile(4) = "ole32.dll"
SysFile(5) = "kernel32.dll"
SysFile(6) = "winmm.dll"
SysFile(7) = "shlwapi.dll"
SysFile(8) = "comdlg32.dll"
SysFile(9) = "shell32.dll"
SysFile(10) = "msvbvm60.dll"
SysFile(11) = "OLEAUT32.dll"
SysFile(12) = "ASYCFILT.dll"
SysFile(13) = "COMCAT.dll"
SysFile(14) = "VB6JP.dll"
SysFile(15) = "scrrun.dll"
SysFile(16) = "dx8vb.dll"
SysFile(17) = "comdlg32.ocx"
SysFile(18) = "MSCOMCTL.ocx"
For i = 0 To 18
hdl = LoadLibrary(SysFile(i))
If hdl = 0 Then
'// 自作ログ書出プロシージャ //
Call DebugOutput("System File of " & SysFile(i) & " is Can't Load Library")
Else
Call FreeLibrary(hdl)
End If
Next
End Sub
ツイート | ![]() |