web-dev-qa-db-ja.com

VBAコードを64ビットWindowsと互換性を持たせるにはどうすればよいですか?

Excel 2007で開発されたVBAアプリケーションがあり、ShellExecute関数へのアクセスを許可する次のコードが含まれていますShell32.dll

Private Declare Function ShellExecute Lib "Shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

私はもともと言った:

どうやら、アプリケーションは64ビットバージョンのWindows(まだ32ビットのOffice 2007を使用)ではコンパイルされません。これは、Declare宣言を更新する必要があるためだと思います。

Office 2010が新しいVBAランタイム(VB7)を導入したこと、およびこれにDeclareステートメントで使用できる新しいキーワードがあり、64ビットWindowsで適切に動作できることを読みました。 VB7には、アプリケーションが32ビットWindowsで実行されているか64ビットWindowsで実行されているかに応じて、古い宣言または新しい宣言が使用される条件付きコンパイルをサポートする新しい定義済みコンパイラ定数もあります。

ただし、Office 2007にこだわっているため、代替ソリューションが必要です。私のオプションは何ですか? (可能な限り、アプリケーションの2つの別個のバージョンをリリースする必要はありません)。

ただし、以下のデイビッドの回答によると、Declareステートメントが機能しない状況については間違っていました。動作しない唯一の状況は、Windows 64ビット上のOffice 2010 64ビットです。したがって、Office 2007は問題ではありません。

32
Gary McGill

Office 2010を搭載した新しい64ビットマシンで社内ツールを使用している人々で、この問題に既に遭遇しています。

私がしなければならなかったのは、次のようなコード行を変更することだけでした。

Private Declare Function ShellExecute Lib "Shell32.dll" Alias "ShellExecuteA" _
    (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

これに:

#If VBA7 Then
    Private Declare PtrSafe Function ShellExecute Lib "Shell32.dll" Alias "ShellExecuteA" _
        (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#Else
    Private Declare Function ShellExecute Lib "Shell32.dll" Alias "ShellExecuteA" _
        (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
#End If

もちろん、使用しているライブラリが両方のマシンで使用可能であることを確認する必要がありますが、これまでのところ、私が使用したことは問題になりませんでした。

古いVB6では、PtrSafeは有効なコマンドではないため、コンパイルエラーがあるかのように赤で表示されますが、コンパイラは最初の部分をスキップするため、実際にはエラーを表示しません。 ifブロック。

code Appearance

上記のコードを使用するアプリケーションは、32ビットおよび64ビットのOffice 2003、2007、2010で完全にコンパイルおよび実行されます。

55
Alain

Office 2007は32ビットのみなので、問題はありません。問題は、32ビットバージョンと64ビットバージョンの両方があるOffice 64ビットでのみ発生します。

Office 2007のみを使用している場合、64ビットOffice 2010でユーザーをサポートすることは望みません。解決策はアップグレードすることです。

唯一のDeclareShellExecuteである場合、64ビットのOfficeを取得すればすることはあまりありませんが、可能な場合にユーザーをサポートすることは現実的ではありません。出荷するプログラムを実行しないでください!彼らがバグを報告したときにあなたが何をするかを考えてください。

4
David Heffernan

私はこのコードを見つけました(いくつかのLongLongPtrに変更されていることに注意してください):

Declare PtrSafe Function ShellExecute Lib "Shell32.dll" _
Alias "ShellExecuteA" (ByVal hwnd As LongPtr, ByVal lpOperation As String, _
ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As _
String, ByVal nShowCmd As Long) As LongPtr

ソース: http://www.cadsharp.com/docs/Win32API_PtrSafe.txt

4

PtrSafeを使用して、Excel 2010での動作を確認してください。

本「Microsoft Excel 2010 Power Programming with VBA」の誤植を修正しました。

#If vba7 and win64 then
  declare ptrsafe function ....
#Else
  declare function ....
#End If

val(application.version)> 12. Office 2010には32ビットバージョンと64ビットバージョンの両方があるため動作しません

3
Jon49

実際には、32ビットまたは64ビットプラットフォームをチェックする正しい方法は、VBAのすべてのバージョン(16ビット、32ビット、および64ビットバージョン)で定義されているWin64定数を使用することです。

#If Win64 Then 
' Win64=true, Win32=true, Win16= false 
#ElseIf Win32 Then 
' Win32=true, Win16=false 
#Else 
' Win16=true 
#End If

ソース:コンパイラ定数に関するVBAヘルプ

2
Dee Bee

Officeのすべてのバージョンを記述するには、新しいVBA7とWin64の条件付きコンパイラ定数の組み合わせを使用します。

VBA7は、コードがVBエディター(Office 2010+で出荷されたVBAバージョン))のバージョン7で実行されているかどうかを判別します。

Win64は、実行しているOfficeのバージョン(32ビットまたは64ビット)を決定します。

#If VBA7 Then
'Code is running VBA7 (2010 or later).

     #If Win64 Then
     'Code is running in 64-bit version of Microsoft Office.
     #Else
     'Code is running in 32-bit version of Microsoft Office.
     #End If

#Else
'Code is running VBA6 (2007 or earlier).

#End If

詳細については、 Microsoftサポート記事 を参照してください。

0
GollyJer

私のためのこの仕事:

#If VBA7 And Win64 Then
    Private Declare PtrSafe Function ShellExecuteA Lib "Shell32.dll" _
        (ByVal hwnd As Long, _
        ByVal lpOperation As String, _
        ByVal lpFile As String, _
       ByVal lpParameters As String, _
        ByVal lpDirectory As String, _
        ByVal nShowCmd As Long) As Long
#Else

    Private Declare Function ShellExecuteA Lib "Shell32.dll" _
        (ByVal hwnd As Long, _
        ByVal lpOperation As String, _
        ByVal lpFile As String, _
        ByVal lpParameters As String, _
        ByVal lpDirectory As String, _
        ByVal nShowCmd As Long) As Long
#End If

洞察力についてJon49に感謝します。

この答えは、コンテキストが間違っている可能性があります。 VBAは最近CLRで実行されると思いますが、そうではありません。いずれにせよ、この返信はsomeoneにとって有用かもしれません。か否か。


Office 2010 32ビットモードを実行する場合、Office 2007と同じです(「問題」はOfficeが64ビットモードで実行されていることです)。ここで重要なのは実行コンテキスト(VBA/CLR)のビット数であり、ロードされたVBA/CLRのビット数はホストプロセスのビット数に依存します。

32/64ビットコール間で最も問題となるのは、long(ビット数に基づく動的なサイズ)の代わりにintまたはIntPtr(CLRで一定サイズ)を使用することです。 )「ポインタータイプ」の場合。

ShellExecute 関数には次のシグネチャがあります。

HINSTANCE ShellExecute(
  __in_opt  HWND hwnd,
  __in_opt  LPCTSTR lpOperation,
  __in      LPCTSTR lpFile,
  __in_opt  LPCTSTR lpParameters,
  __in_opt  LPCTSTR lpDirectory,
  __in      INT nShowCmd
);

この場合、HWNDがIntPtrであることが重要です(これは [〜#〜] hwnd [〜#〜]void*/"void pointer")であり、longではありません。例として pinvoke.net ShellExecute を参照してください。 (いくつかの「ソリューション」はpinvoke.netで日陰になっていますが、最初に見るのに適した場所です)。

ハッピーコーディング。


「新しい構文」に関する限り、私にはわからない。

0
user166390