by イグトランス » 2006年3月11日(土) 00:33
> Declare Function VerQueryValue Lib "Version.dll" _
> Alias "VerQueryValueA" _
上の行で下線が抜けているのがエラーになりました。
あと全角スペースがあるというエラーがどこかでありましたが,
その行の空白を一旦全て削除し,タブや半角スペースを挿入しなおして対処しました。
それだけで実行できましたが,VB由来の部分をAB風に直してみます。
つまりABの特徴を生かすようにするということです。
クリックすると表示されます。細々としたことが多いです。 [ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]まずいちいちWin32apiResultCodeへ代入していますが,ABではその必要はありません。
コード: 全て選択
Type CODEPAGE
cpLOW As Integer
cpHIGH As Integer
End Type
C/C++の例を探すと皆WORD型を使っています。VBにはそれに相当する型が無いのでIntegerにしているのでしょうけど,ABにはWordがあります。
GetFileVersionInfoの宣言(Declare)の最後の引数ByRef lpData As AnyはByVal lpData As VoidPtrの方が今回は都合が良いです。
するとこれが(If ~ Thenの次の行)
コード: 全て選択
GetFileVersionInfo(strTargetFileName, 0, _
SizeOfVersionInfo, bytDummyVersionInfo[0])
こうできます。
コード: 全て選択
GetFileVersionInfo(strTargetFileName, 0,
Len(bytDummyVersionInfo), bytDummyVersionInfo)
最後の引数が参照渡し(ByRef)でなくポインタの値渡しになったので[0]が消えました。
VarPtr(bytDummyVersionInfo[0])と書いても同じです。
また,3番目の引数があれでは,もしSizeOfVersionInfoがbytDummyVersionInfoの要素数より多かった場合,配列の本来の要素数よりも多くのデータが書き込まれてしまいます。バッファオーバーフローというやつです。
(たとえその可能性が低いとしても可能性があるというのは良くないことです)
SizeOfVersionInfoの値に合わせて動的確保するのが適切ですが,私はそこまで手を付けないことにします。
コード: 全て選択
Declare Function VerQueryValue Lib "Version.dll" _
Alias "VerQueryValueA" _
(pBlock As VoidPtr, ByVal lpSubBlock As String, _
ByVal lplpBuffer As *VoidPtr, ByRef puLen As DWord) As DWord
VerQueryValueの宣言の3番目の引数をByValにしました。
ABでは構造体へのポインタがあるのでこうできます。
まずtypCODEPAGEの宣言をDim pCodePage As *CODEPAGEとします。
コード: 全て選択
VerQueryValue(bytDummyVersionInfo,
"\VarFileInfo\Translation", VarPtr(typCODEPAGE), LengthVersionInfo)
さらにtypCODEPAGEの変数宣言をDim pCodePage As *CODEPAGEとします。
するとこれは
コード: 全て選択
Win32apiResultCode = VerQueryValue(bytDummyVersionInfo[], _
"\VarFileInfo\Translation", PointerVersionInfo, LengthVersionInfo)
memcpy(VarPtr(typCODEPAGE), PointerVersionInfo, LengthVersionInfo)
こうできます。
コード: 全て選択
Win32apiResultCode = VerQueryValue(bytDummyVersionInfo,
"\VarFileInfo\Translation", VarPtr(pCodePage), LengthVersionInfo)
後はtypCODEPAGE.をpCodePage->に置き換えます。
コード: 全て選択
Dim strPath As String
' 中略
strPathFull = strPath + "ProductName"
中々回りくどいですね。なるほどVBではそうするかという思いが伝わってきます。
ABではこのとおり2行で済みます。
コード: 全て選択
Dim szFullPath[ELM(1024)] As Byte ' きちんとした大きさを計るのが面倒なんでwsprintfの限界値にしておく。
wsprintf(szFullPath, "\StringFileInfo\%04X%04X\ProductName", pCodePage->cpLOW, pCodePage->cpHIGH)
szFullPathがstrPathFullに相当します。
コード: 全て選択
strTemp = Space$(LengthVersionInfo)
memcpy(StrPtr(strTemp), PointerVersionInfo, LengthVersionInfo)
わざわざString型に持ってくる必要はありません。
ポインタをそのまま文字列へのポインタとして見なせば何もすることはありません。
ただMsgBoxを念のためAPIのMessageBoxにします。手前のIfの条件も変更する必要があります。
結果こうなりました。
[ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]コード: 全て選択
#strict
Declare Function GetFileVersionInfoSize Lib "Version.dll" _
Alias "GetFileVersionInfoSizeA" _
(ByVal lptstrFilename As String, ByRef lpdwHandle As DWord) As DWord
Declare Function GetFileVersionInfo Lib "Version.dll" _
Alias "GetFileVersionInfoA" _
(ByVal lptstrFilename As String, ByVal dwHandle As DWord, _
ByVal dwLen As DWord, ByVal lpData As VoidPtr) As DWord
Declare Function VerQueryValue Lib "Version.dll" _
Alias "VerQueryValueA" _
(pBlock As VoidPtr, ByVal lpSubBlock As String, _
ByVal lplpBuffer As *VoidPtr, ByRef puLen As DWord) As DWord
Type CODEPAGE
cpLOW As Word
cpHIGH As Word
End Type
Sub MainWnd_CommandButton1_Click()
Dim strTargetFileName As String
Dim SizeOfVersionInfo As DWord
Dim DummyHandle As DWord
Dim bytDummyVersionInfo[2048] As Byte
Dim pszVersionInfo As BytePtr
Dim LengthVersionInfo As DWord
Dim pCodePage As *CODEPAGE
strTargetFileName = "C:\WINDOWS\system32\calc.exe"
SizeOfVersionInfo = GetFileVersionInfoSize(strTargetFileName, _
DummyHandle)
If SizeOfVersionInfo > 0 Then
GetFileVersionInfo(strTargetFileName, 0, _
SizeOfVersionInfo, bytDummyVersionInfo)
VerQueryValue(bytDummyVersionInfo, _
"\VarFileInfo\Translation", VarPtr(pCodePage), LengthVersionInfo)
Dim szFullPath[ELM(1024)] As Byte ' きちんとした大きさを計るのが面倒なんでwsprintfの限界値にしておく。
wsprintf(szFullPath, "\StringFileInfo\%04X%04X\ProductName",
pCodePage->cpLOW, pCodePage->cpHIGH)
VerQueryValue(bytDummyVersionInfo,
szFullPath, VarPtr(pszVersionInfo), LengthVersionInfo)
If pszVersionInfo[0] <> 0 Then '長さ1以上かどうかを1文字目が文字列の終わりかどうかの判断に代えてある。
MessageBox(hMainWnd, pszVersionInfo, "", MB_OK)
End If
End If
End Sub
> Declare Function VerQueryValue Lib "Version.dll" _
> Alias "VerQueryValueA" _
上の行で下線が抜けているのがエラーになりました。
あと全角スペースがあるというエラーがどこかでありましたが,
その行の空白を一旦全て削除し,タブや半角スペースを挿入しなおして対処しました。
それだけで実行できましたが,VB由来の部分をAB風に直してみます。
つまりABの特徴を生かすようにするということです。
[hide=クリックすると表示されます。細々としたことが多いです。]まずいちいちWin32apiResultCodeへ代入していますが,ABではその必要はありません。
[code]Type CODEPAGE
cpLOW As Integer
cpHIGH As Integer
End Type[/code]
C/C++の例を探すと皆WORD型を使っています。VBにはそれに相当する型が無いのでIntegerにしているのでしょうけど,ABにはWordがあります。
GetFileVersionInfoの宣言(Declare)の最後の引数ByRef lpData As AnyはByVal lpData As VoidPtrの方が今回は都合が良いです。
するとこれが(If ~ Thenの次の行)
[code]GetFileVersionInfo(strTargetFileName, 0, _
SizeOfVersionInfo, bytDummyVersionInfo[0])[/code]
こうできます。[code]GetFileVersionInfo(strTargetFileName, 0,
Len(bytDummyVersionInfo), bytDummyVersionInfo)[/code]
最後の引数が参照渡し(ByRef)でなくポインタの値渡しになったので[0]が消えました。
VarPtr(bytDummyVersionInfo[0])と書いても同じです。
また,3番目の引数があれでは,もしSizeOfVersionInfoがbytDummyVersionInfoの要素数より多かった場合,配列の本来の要素数よりも多くのデータが書き込まれてしまいます。バッファオーバーフローというやつです。
(たとえその可能性が低いとしても可能性があるというのは良くないことです)
SizeOfVersionInfoの値に合わせて動的確保するのが適切ですが,私はそこまで手を付けないことにします。
[code]Declare Function VerQueryValue Lib "Version.dll" _
Alias "VerQueryValueA" _
(pBlock As VoidPtr, ByVal lpSubBlock As String, _
ByVal lplpBuffer As *VoidPtr, ByRef puLen As DWord) As DWord[/code]
VerQueryValueの宣言の3番目の引数をByValにしました。
ABでは構造体へのポインタがあるのでこうできます。
まずtypCODEPAGEの宣言をDim pCodePage As *CODEPAGEとします。
[code]VerQueryValue(bytDummyVersionInfo,
"\VarFileInfo\Translation", VarPtr(typCODEPAGE), LengthVersionInfo)[/code]
さらにtypCODEPAGEの変数宣言をDim pCodePage As *CODEPAGEとします。
するとこれは
[code]Win32apiResultCode = VerQueryValue(bytDummyVersionInfo[], _
"\VarFileInfo\Translation", PointerVersionInfo, LengthVersionInfo)
memcpy(VarPtr(typCODEPAGE), PointerVersionInfo, LengthVersionInfo)[/code]
こうできます。
[code]Win32apiResultCode = VerQueryValue(bytDummyVersionInfo,
"\VarFileInfo\Translation", VarPtr(pCodePage), LengthVersionInfo)[/code]
後はtypCODEPAGE.をpCodePage->に置き換えます。
[code]Dim strPath As String
' 中略
strPathFull = strPath + "ProductName"[/code]
中々回りくどいですね。なるほどVBではそうするかという思いが伝わってきます。
ABではこのとおり2行で済みます。
[code]Dim szFullPath[ELM(1024)] As Byte ' きちんとした大きさを計るのが面倒なんでwsprintfの限界値にしておく。
wsprintf(szFullPath, "\StringFileInfo\%04X%04X\ProductName", pCodePage->cpLOW, pCodePage->cpHIGH)[/code]
szFullPathがstrPathFullに相当します。
[code]strTemp = Space$(LengthVersionInfo)
memcpy(StrPtr(strTemp), PointerVersionInfo, LengthVersionInfo) [/code]わざわざString型に持ってくる必要はありません。
ポインタをそのまま文字列へのポインタとして見なせば何もすることはありません。
ただMsgBoxを念のためAPIのMessageBoxにします。手前のIfの条件も変更する必要があります。[/hide]
結果こうなりました。
[hide][code]#strict
Declare Function GetFileVersionInfoSize Lib "Version.dll" _
Alias "GetFileVersionInfoSizeA" _
(ByVal lptstrFilename As String, ByRef lpdwHandle As DWord) As DWord
Declare Function GetFileVersionInfo Lib "Version.dll" _
Alias "GetFileVersionInfoA" _
(ByVal lptstrFilename As String, ByVal dwHandle As DWord, _
ByVal dwLen As DWord, ByVal lpData As VoidPtr) As DWord
Declare Function VerQueryValue Lib "Version.dll" _
Alias "VerQueryValueA" _
(pBlock As VoidPtr, ByVal lpSubBlock As String, _
ByVal lplpBuffer As *VoidPtr, ByRef puLen As DWord) As DWord
Type CODEPAGE
cpLOW As Word
cpHIGH As Word
End Type
Sub MainWnd_CommandButton1_Click()
Dim strTargetFileName As String
Dim SizeOfVersionInfo As DWord
Dim DummyHandle As DWord
Dim bytDummyVersionInfo[2048] As Byte
Dim pszVersionInfo As BytePtr
Dim LengthVersionInfo As DWord
Dim pCodePage As *CODEPAGE
strTargetFileName = "C:\WINDOWS\system32\calc.exe"
SizeOfVersionInfo = GetFileVersionInfoSize(strTargetFileName, _
DummyHandle)
If SizeOfVersionInfo > 0 Then
GetFileVersionInfo(strTargetFileName, 0, _
SizeOfVersionInfo, bytDummyVersionInfo)
VerQueryValue(bytDummyVersionInfo, _
"\VarFileInfo\Translation", VarPtr(pCodePage), LengthVersionInfo)
Dim szFullPath[ELM(1024)] As Byte ' きちんとした大きさを計るのが面倒なんでwsprintfの限界値にしておく。
wsprintf(szFullPath, "\StringFileInfo\%04X%04X\ProductName",
pCodePage->cpLOW, pCodePage->cpHIGH)
VerQueryValue(bytDummyVersionInfo,
szFullPath, VarPtr(pszVersionInfo), LengthVersionInfo)
If pszVersionInfo[0] <> 0 Then '長さ1以上かどうかを1文字目が文字列の終わりかどうかの判断に代えてある。
MessageBox(hMainWnd, pszVersionInfo, "", MB_OK)
End If
End If
End Sub [/code][/hide]