アプリ版:「スタンプのみでお礼する」機能のリリースについて

今までExcel2000のVBAから、以下のようなコードを使ってC++で作ったコマンドプロンプトで動くプログラムを動かすプログラムを作っていましたが、これを64bitのWindows7上で動いているExcel2010で使おうとしたらメッセージが出ました。いろいろ調べてみたところ、たぶんDeclareにPtrSafeを付ければ良いようなのですが、その際、他のコードはそのままで良いのでしょうか。特に、コード中のLongはそのままで良いのか気になるのですが...。ちなみに、下記コードの条件コンパイルはネットで調べて見よう見まねで付けたもので、Excel2000のときには付けていないものでした。ご存じの方がいらっしゃいましたらご教授ください。

'------------------------------------------------------------------------------
' Win32 API関数・定数の宣言
'------------------------------------------------------------------------------
#If VBA7 And Win64 Then '64bit

Declare PtrSafe Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, _
  ByVal dwMilliseconds As Long) As Long

Declare PtrSafe Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, _
  ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long

Declare PtrSafe Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

#Else '32bit

Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, _
  ByVal dwMilliseconds As Long) As Long

Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, _
  ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long

Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

#End If

Private Const PROCESS_ALL_ACCESS As Long = &H1F0FFF
Private Const INFINITE As Long = &HFFFF

'------------------------------------------------------------------------------
' Run
'------------------------------------------------------------------------------
Public Sub Run(ByVal project_name As String)
  Dim program As String
  Dim task_id As Long
  Dim h_proc As Variant

  program = mdlFunc.ProgramPath() & mdlFunc.ProgramOption(project_name) 'プログラム名

  task_id = Shell(program, vbHide)
  h_proc = OpenProcess(PROCESS_ALL_ACCESS, False, task_id)

  If OpenProcess(PROCESS_ALL_ACCESS, False, task_id) <> vbNull Then
    Call WaitForSingleObject(h_proc, INFINITE)
    CloseHandle h_proc
  End If

End Sub

A 回答 (3件)

LongPtrの補足ですが、


32bit環境で動かした場合は、LongPtrは32bit、
64bit環境で動かした場合は、LongPtrは64bitとして扱われます。

上記の通りポインタは大きさが変わる物で、他言語ではある程度流動的に変わる仕様なのですが、
VB(VBA)の整数型(int, long)は常に大きさが変わらない仕様であったため、
今回のような事になったのでしょう。

>> OpenProcessの戻り値もアドレスなのでLongPtrにする必要がある
はい、そうです。

>> 1. かつてのVBAではポインタ(32bit)を扱う型が無かったので、同じ32bitであるLongで代用していた。
>> 2. 64bit環境ではアドレスが64bitになるので、32bitのLongに格納するとデータが欠落する。
>> 3. これの対策としてポインタとしてのLongPtrという型が追加された。
>> 4. 今回のプログラムの場合、OpenProcessがプロセスハンドルとしてアドレスを返す。
はい、そうです。

>> 5. これを受け取るデータ型はVariantなので問題ないが(自動で判別するから?)、
>> WaitForSingleObjectの第1引数及びCloseHandleには64bitのポインタを渡す必要がある。
Variantで問題があるかどうかは分かりませんが、
OpenProcess関数はHANDLE型を返しますので、受け側(h_proc)はLongPtrが適切だと思います。

>> 6. 結果、WaitForSingleObjectの第1引数とCloseHandleの引数をLongPtrにする必要がある。
はい、そうです。

参考URL:http://msdn.microsoft.com/ja-jp/library/ee691831 …
    • good
    • 0
この回答へのお礼

丁寧にお教えいただきありがとうございました。詳細なことはこれから勉強しようと思いますが、今回のポインタの件は何となく理解できたような気がします。

お礼日時:2012/03/28 04:40

こんにちは。


APIの宣言自体は、Win32API_PtrSafe.TXTから持って来ればいいです。
http://www.microsoft.com/download/en/details.asp …
C:\Office 2010 Developer Resources\Documents\Office2010Win32API_PtrSafe\Win32API_PtrSafe.TXT

# それと、コード中のおかしな所は、直しました。

Public Sub Run(ByVal project_name As String)
  Dim program As String
  Dim task_id As Long
  Dim h_proc As LongPtr

  program = mdlFunc.ProgramPath() & mdlFunc.ProgramOption(project_name) 'プログラム名

  task_id = Shell(program, vbHide)
  h_proc = OpenProcess(PROCESS_ALL_ACCESS, 1, task_id)

  If h_proc <> 0 Then
    Call WaitForSingleObject(h_proc, INFINITE)
    CloseHandle h_proc
  End If

End Sub
    • good
    • 0
この回答へのお礼

ご回答いただきましてありがとうございます。ご紹介いただきましたtxtデータを見てみました。少しずつ勉強してみます。

お礼日時:2012/03/28 04:38

ざっと見ておかしいのは、(*)のLongです。


64bit環境になってからは、これをLongPtrにする必要があるかと。

Declare PtrSafe Function WaitForSingleObject Lib "kernel32"(
 ByVal hHandle As Long(*),
 ByVal dwMilliseconds As Long) As Long

dwMilliseconds側のLongはそのままです。
他も同様に、数値の値としてのLongはそのままで、ポインタやハンドルとしてのLongはLongPtrにしてみてください。

この回答への補足

追加ですみません。OpenProcessの戻り値もアドレスなのでLongPtrにする必要がある、という理解で間違いないでしょうか。

補足日時:2012/03/27 08:59
    • good
    • 0
この回答へのお礼

ご回答いただきありがとうございます。いまいち正しく理解できているか判らないので確認させてください。

1. かつてのVBAではポインタ(32bit)を扱う型が無かったので、同じ32bitであるLongで代用していた。

2. 64bit環境ではアドレスが64bitになるので、32bitのLongに格納するとデータが欠落する。

3. これの対策としてポインタとしてのLongPtrという型が追加された。

4. 今回のプログラムの場合、OpenProcessがプロセスハンドルとしてアドレスを返す。

5. これを受け取るデータ型はVariantなので問題ないが(自動で判別するから?)、WaitForSingleObjectの第1引数及びCloseHandleには64bitのポインタを渡す必要がある。

6. 結果、WaitForSingleObjectの第1引数とCloseHandleの引数をLongPtrにする必要がある。

以上で間違いないでしょうか。お時間があれば確認していただけると幸いです。よろしくお願いいたします。

お礼日時:2012/03/27 08:54

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています