SPIRITさんのActiveBasic講座のウィンドウを半透明にする(Win2000以上) をためさせていただきました。(いつも参考にさせていただいてます)
http://www.geocities.jp/skynet3113/data ... tml#Window
サンプル自体は問題なく成功したのですが、XPでコンパイルしたEXEを95、98環境で実行させたとき、透過の機能を使わないようにしたいのです。
Win2000以前のOSの時はスキップさせようと、Winのバージョン判定し、透過のコードの方はIFでスルーする様にできたのですが、
Declare Function SetLayeredWindowAttributes Lib "user32" (hwnd As Long,crKey As Long, bAlpha As Byte,dwFlags As Long) As Long
EXEを実行した時上記部分でプログラム開始エラーとなってしまいます。98・XP両方で使える様にするにはどのようにすればよいのでしょうか?
98SEでもエラーが出ないPCと、出るPCがあるのも謎です。
欠落エクスポートを回避するには
明示的リンクをすれば良いです
Declareで宣言したDLL関数はプログラムの実行開始時にその関数が見つからないといけません。
SetLayeredWindowAttributesはWindows 2000以上にのみ存在する関数ですから,
Windows 98などではそれが存在せず実行が開始できないのです。
どうするかというと,明示的リンクをすることになります。
プログラムのはじめ(Createイベントなど)でLoadLibraryを行い,
GetProcAddressでSetLayeredWindowAttributesのアドレスを入手します。
そのアドレスは関数へのポインタの変数へ代入することでその関数を呼ぶことができます。
Windows 98などではGetProcAddressがNULLを返すので,それに気を付ければ良いだけです。
もちろんFreeLibraryを忘れてはいけません。
SetLayeredWindowAttributesはWindows 2000以上にのみ存在する関数ですから,
Windows 98などではそれが存在せず実行が開始できないのです。
どうするかというと,明示的リンクをすることになります。
プログラムのはじめ(Createイベントなど)でLoadLibraryを行い,
GetProcAddressでSetLayeredWindowAttributesのアドレスを入手します。
そのアドレスは関数へのポインタの変数へ代入することでその関数を呼ぶことができます。
Windows 98などではGetProcAddressがNULLを返すので,それに気を付ければ良いだけです。
もちろんFreeLibraryを忘れてはいけません。
Re: 明示的リンクをすれば良いです
イグトランスさんこんにちは
> プログラムのはじめ(Createイベントなど)でLoadLibraryを行い,
> GetProcAddressでSetLayeredWindowAttributesのアドレスを入手します。
> そのアドレスは関数へのポインタの変数へ代入することでその関数を呼ぶことができます。
> Windows 98などではGetProcAddressがNULLを返すので,それに気を付ければ良いだけです。
>
> もちろんFreeLibraryを忘れてはいけません。
結構大変なんですね。LoadLibrayにて検索して試してみようと思います。ありがとうございました。
> プログラムのはじめ(Createイベントなど)でLoadLibraryを行い,
> GetProcAddressでSetLayeredWindowAttributesのアドレスを入手します。
> そのアドレスは関数へのポインタの変数へ代入することでその関数を呼ぶことができます。
> Windows 98などではGetProcAddressがNULLを返すので,それに気を付ければ良いだけです。
>
> もちろんFreeLibraryを忘れてはいけません。
結構大変なんですね。LoadLibrayにて検索して試してみようと思います。ありがとうございました。
できました。
結果的にこのようにしたら動的リンクができました。まだ98にてのテストは行っていませんが、大丈夫だと思うんだけどなー
[ここをクリックすると内容が表示されます]
'透過設定
'Dim hModule As HINSTANCE
'架空の関数を宣言(SetLayeredWindowAttributesの宣言を参考にして作成)
TypeDef SetLWA = *Function(hwnd As HWND,crKey As Long,bAlpha As BYTE ,dwFlags As DWORD ) As Integer
Dim DamSetLayeredWindowAttributes As SetLWA
'DLLを動的にロード
hModule=LoadLibrary("user32.dll")
IF hModule<>0 Then 'hModule=0 のときDLLがないので終了
'関数のアドレスを取得
DamSetLayeredWindowAttributes=GetProcAddress(hModule,"SetLayeredWindowAttributes")
'透過設定 SPRITさんホームページより
SetWindowLong(hMainWnd, GWL_EXSTYLE, GetWindowLong(hMainWnd, GWL_EXSTYLE) or &H80000)
if Toukasuru =1 then
'ポインタを使って関数を実行します
DamSetLayeredWindowAttributes(hMainWnd,0,Int(Toukaritu*255/100),LWA_ALPHA)
SetLayeredWindowAttributes(hMainWnd,0,Int(Toukaritu*255/100),LWA_ALPHA)
'第3引数 0(薄い)~255(濃い)を変えると、透過度が変わります。
Else
DamSetLayeredWindowAttributes(hMainWnd,0,255,LWA_ALPHA)
End If
End If
'DLLを開放
FreeLibrary(hModule)
'Dim hModule As HINSTANCE
'架空の関数を宣言(SetLayeredWindowAttributesの宣言を参考にして作成)
TypeDef SetLWA = *Function(hwnd As HWND,crKey As Long,bAlpha As BYTE ,dwFlags As DWORD ) As Integer
Dim DamSetLayeredWindowAttributes As SetLWA
'DLLを動的にロード
hModule=LoadLibrary("user32.dll")
IF hModule<>0 Then 'hModule=0 のときDLLがないので終了
'関数のアドレスを取得
DamSetLayeredWindowAttributes=GetProcAddress(hModule,"SetLayeredWindowAttributes")
'透過設定 SPRITさんホームページより
SetWindowLong(hMainWnd, GWL_EXSTYLE, GetWindowLong(hMainWnd, GWL_EXSTYLE) or &H80000)
if Toukasuru =1 then
'ポインタを使って関数を実行します
DamSetLayeredWindowAttributes(hMainWnd,0,Int(Toukaritu*255/100),LWA_ALPHA)
SetLayeredWindowAttributes(hMainWnd,0,Int(Toukaritu*255/100),LWA_ALPHA)
'第3引数 0(薄い)~255(濃い)を変えると、透過度が変わります。
Else
DamSetLayeredWindowAttributes(hMainWnd,0,255,LWA_ALPHA)
End If
End If
'DLLを開放
FreeLibrary(hModule)
試しにWindows 98で実行してみましたが,落ちます。
Windows 98もuser32.dllはあります。しかし,SetLayeredWindowAttributesは無いのでGetProcAddressはNULLを返すからです。
つまりDamSetLayeredWindowAttributesがNULLかどうかを確かめるのも必要です。
また,これは私がうっかりしていたことですが,ウィンドウを使うプログラムにおいて,
user32.dllは常に読み込まれて(ロードされて)いると仮定してよいのです。
(CreateWindowなどウィンドウプログラミングに必須の関数がuser32.dllにあり,それらをDeclareして使っているので)
こういうときはLoadLibraryの代わりにGetModuleHandle("user32.dll")が使えます。
するとFreeLibraryをする必要はありません。
Windows 98もuser32.dllはあります。しかし,SetLayeredWindowAttributesは無いのでGetProcAddressはNULLを返すからです。
つまりDamSetLayeredWindowAttributesがNULLかどうかを確かめるのも必要です。
また,これは私がうっかりしていたことですが,ウィンドウを使うプログラムにおいて,
user32.dllは常に読み込まれて(ロードされて)いると仮定してよいのです。
(CreateWindowなどウィンドウプログラミングに必須の関数がuser32.dllにあり,それらをDeclareして使っているので)
こういうときはLoadLibraryの代わりにGetModuleHandle("user32.dll")が使えます。
するとFreeLibraryをする必要はありません。
すばやい検証ありがとうございます。
わざわざ時間をとって試していただいてすいません。
今はuser32.dllが有るか無いかをみていて、98でもあるので×
user32.dllの中にSetLayeredWindowAttributes関数がアルカナイカ
を見るわけですね。
また試してみます。
今はuser32.dllが有るか無いかをみていて、98でもあるので×
user32.dllの中にSetLayeredWindowAttributes関数がアルカナイカ
を見るわけですね。
また試してみます。
MainWnd_Createに書いた以前のコードに追加して自宅の98で確認しました。
時間がたって読みかえしたときずいぶんまごつきそうです。たくさんコメントかいていますが、もっとすっきりした書き方があるのでしょうね。
動いて何ぼということでいつも自分をなぐさめています。
今回も希望の機能が実現できました、ありがとうございました。
時間がたって読みかえしたときずいぶんまごつきそうです。たくさんコメントかいていますが、もっとすっきりした書き方があるのでしょうね。
動いて何ぼということでいつも自分をなぐさめています。
今回も希望の機能が実現できました、ありがとうございました。
[ここをクリックすると内容が表示されます]
コード: 全て選択
'透過設定
'Dim hModule As HINSTANCE
'架空の関数を宣言(SetLayeredWindowAttributesの宣言を参考にして作成)
TypeDef SetLWA = *Function(hwnd As HWND,crKey As Long,bAlpha As BYTE ,dwFlags As DWORD ) As Integer
Dim DamSetLayeredWindowAttributes As SetLWA
'DLLを動的にロード
hModule=LoadLibrary("user32.dll")
IF hModule<>0 Then 'hModule=0 のときDLLがないので終了
'関数のアドレスを取得
DamSetLayeredWindowAttributes=GetProcAddress(hModule,"SetLayeredWindowAttributes")
'ここから
If DamSetLayeredWindowAttributes=0 then
FreeLibrary(hModule)
exit sub
End If
'ここまでを追加
'透過設定 SPRITさんホームページより
SetWindowLong(hMainWnd, GWL_EXSTYLE, GetWindowLong(hMainWnd, GWL_EXSTYLE) or &H80000)
if Toukasuru =1 then
'ポインタを使って関数を実行します
DamSetLayeredWindowAttributes(hMainWnd,0,Int(Toukaritu*255/100),LWA_ALPHA)
SetLayeredWindowAttributes(hMainWnd,0,Int(Toukaritu*255/100),LWA_ALPHA)
'第3引数 0(薄い)~255(濃い)を変えると、透過度が変わります。
Else
DamSetLayeredWindowAttributes(hMainWnd,0,255,LWA_ALPHA)
End If
End If
'DLLを開放
FreeLibrary(hModule)