システム開発ブログ

VBA

Windows

システム開発

WinAPIの32bitと64bit

みなさん、こんにちは。

長年使用しているWindowsAPIですが、あまり理解せずに使っていたなと思うことがあったので書き残しておきます。

Windows APIとはWindowsで提供されているDLLに含まれるアプリケーションから呼び出し可能な関数のことを指すと言ってよいですかね。
この関数を呼び出す際には、Declareステートメントを利用して参照宣言を行います。

開発で使用するパソコンが64bit版が主流になったのをきっかけに、64bitOSでWindowsAPIを使用する場合は、PtrSafeキーワードを使用するというのを単なる決めごとのようにして覚えていました。
MSDNからの抜粋によると、PtrSafeとは以下のキーワードとなるそうです。

PtrSafe キーワードは、 Declare ステートメントを 64 ビットの開発環境で安全に実行できることを示すキーワードです。

今回遭遇したのは、GetOpenFileName関数がPtrSafeを入れただけでは動かないという事象です。
GetOpenFileName関数はファイル指定ダイアログを使用するための関数です。
20181113folder.PNG

GetOpenFileName関数を使用するには以下の関数と構造体の宣言が必要です。

Private Type OPENFILENAME
        lStructSize As Long
        hwndOwner As Long
        hInstance As Long
        lpstrFilter As String
        lpstrCustomFilter As String
        nMaxCustFilter As Long
        nFilterIndex As Long
        lpstrFile As String
        nMaxFile As Long
        lpstrFileTitle As String
        nMaxFileTitle As Long
        lpstrInitialDir As String
        lpstrTitle As String
        flags As Long
        nFileOffset As Integer
        nFileExtension As Integer
        lpstrDefExt As String
        lCustData As Long
        lpfnHook As Long
        lpTemplateName As String
End Type
Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long

これを64bitOSに対応させるため以下のように修正しました。

#If Win64 Then
Private Declare PtrSafe Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long
#Else
Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long
#End If

64bitOSでコンパイルエラーは出なくなったものの、実際に動かしてみるとダイアログは表示されず、うんともすんとも動きません。
調べてみたところ、構造体のほうも修正が必要でした。
先に、修正した内容を記載しておくと、以下のように構造体を修正することで解決しました。

Private Type OPENFILENAME
        lStructSize As Long
        hwndOwner As LongPtr
        hInstance As LongPtr
        lpstrFilter As String
        lpstrCustomFilter As String
        nMaxCustFilter As Long
        nFilterIndex As Long
        lpstrFile As String
        nMaxFile As Long
        lpstrFileTitle As String
        nMaxFileTitle As Long
        lpstrInitialDir As String
        lpstrTitle As String
        flags As Long
        nFileOffset As Integer
        nFileExtension As Integer
        lpstrDefExt As String
        lCustData As LongPtr
        lpfnHook As LongPtr
        lpTemplateName As String
End Type

修正内容としては、ハンドルやポインタとして使用されている変数をLongからLongPtrに変更しています。

Longは32bitデータですが、LongPtrは32bitOSではLong、64bitOSでは64bitのLongLong(64bitOSにしか存在しない)に対応するエイリアスとなります。
64bitOSでハンドルやポインタを使用する場合は64bitで戻されるためLongのままだと型エラーもしくはデータが切り捨てられて正しくない値が戻るようです。

このためLongPtrへの書き換えを行うのですが、このLongPtrもvba7(Office2010)以降でないとエラーになるため、Declare宣言と同様に
#If Win64 Then
を使用してOSのビット数により判断を分けたほうが良さそうです。

システム開発の成功メソッドがわかる冊子をお問い合わせで無料プレゼント ≫

この記事に関連する記事の一覧


システム開発ブログ

Twitterでilovex_officialをフォローしてください

カテゴリー

以前の部署別ブログ

ページのトップ