OS:Windows2000
Ver:6.0
ganchanといいます。よろしくお願いします。
AutoCADで作られたファイル「abc.dwg」を開きたいのです。コードは下のとうりです
file_full = "d:\abc.dwg"
sInfo.cb = LenB(sInfo)
ret = CreateProcess(vbNullString, file_full, ByVal 0&, ByVal 0&, _
1&, NORMAL_PRIORITY_CLASS, ByVal 0&, vbNullString, _
sInfo, pInfo)
実行するとretの値がゼロになります。
file_full = "C:\Program Files\ACAD LT 2000\aclt.exe"
にして実行するとretの値が1になり、AutoCADが立ち上がります。
最初の引数vbNullString(lpApplicationName)と2番目の引数file_full
(lpCimmandline)の設定が間違っているのかも知れませんが、よろしくお願いします。
ダブルクリックだと,CreateProcessではなくShellExecute(Ex)です。
で,Shell関数とコマンドプロセッサのStart命令を組み合わせて,
Shell """" & Environ$("COMSPEC") & """ /C START """" """ & file_full & """", vbHide
とやるのも手だと思います。
# Start命令かますのは,コマンドプロセッサを即座に閉じるため。
YuO様、登校ありがとうございます。ファイルを開くことができました。
実は、この先があり、Shell関数の戻り値を変数に保存後、EnumWindowsを使用して
開いたファイルのハンドルを取得しています。取得したハンドルでアプリケーションを閉じたいのです。実行するとShell関数から取得したProcessIDとEnumWindows
のProcessIDが一致しません。Shell関数からのProcessIDの取得がまずいのでしょうか。追加質問になりますが、よろしくお願いします。
Private Sub Command1_Click()
Dim file_full As String
Find_Process = 0
Find_WinWnd = 0
file_full = "d:\abc.dwg"
Find_Process = Shell("""" & Environ$("COMSPEC") & """ _
/C START """" """ & file_full & """", vbHide)
MsgBox "アプリケーションを終了させます。"
Call EnumWindows(AddressOf EnumWinProc, 0&)
If (Find_WinWnd <> 0&) Then
Call SendMessage(Find_WinWnd, WN_CLOSE, 0&, 0&)
End If
End Sub
Public Function EnumWinProc(ByVal hwnd As Long, lParam As Long) _
As Boolean
Dim lngTrd As Long
Dim lngPrs As Long
EnumWinProc = True
If Not (GetParent(ByVal hwnd) = 0) Then GoTo PGMEND
lngTrd = GetWindowThreadProcessId(hwnd, lngPrs)
If lngPrs = Find_Process Then
Find_WinWnd = hwnd
EnumWinProc = False
End If
PGMEND:
End Function
プロセス列挙がウィンドウ作成より早いだけではないでしょうか。
・WaitForInputIdle APIで待ってみる
・時間を空けて複数回試みてみる
などの対策をする必要があると思います。
勘違いがありました。
Shell 関数の戻り値は,「%COMSPEC%」 (NT系なら%WINDIR%\System32\CMD.exe だと思う) のプロセスの ID です。
このプロセスは,Start 内部命令でプログラムを起動した後,すぐさま終了します。
よって,ウィンドウを取得するとなると,
1. ShellExecuteEx API で起動して,プロセスハンドルを取得する
2. GetProcessId API でプロセスIDを取得する
3. 上記の方法で待つ
という手順が必要です。
# Required: Windows XP SP1 or later
YuO様、登校ありがとうございます。
早速ですが、kernel32.dllにGetProcessID関数があるようで
下のようにしました。
[モジュール1]
Public Declare Function GetProcessID Lib "kernel32" _
(ByVal hProcess As Long) As Long
[コマンドボタン1のShellexecutEx関数以降]
lngRet = ShellExecuteEX(sdtSEXI)
Find_Process = GetProcessID(sdtSEXI.hProcess)
GetProcessID関数を実行すると” kernel32”にGetProcessIDは
見つかりません”というメッセージを表示します。
色々調べるとウィルス感染とか出てきました。
現象がよくつかめません。何かあれば教えてください。
よく見てください。
http://msdn.microsoft.com/en-us/library/ms683215.aspx
GetProcessId関数です。
GetProcessID関数ではありません。
Windows APIは識別子に対してCase-Sensitiveです。
いくらVBが識別子に対してCase-Insensitiveでも,Windows APIの呼び出し部分だけはCase-Sensitiveに書かないといけません。
YuO様、投稿ありがとうございます。
添付してありましたホームページを見ました。'GetProcessId'と'kernel32'で
検索し、GetProcessIdのDeclare宣言及び使用する時のコードを確認しましたが、
間違っていないようです。どこがおかしいのですか。また、'Case-Sensitive'の
意味がいまいち分かりません。ご指導の方よろしくお願いします。
> どこがおかしいのですか。
関数名が間違っています。
前に書いた通り,GetProcessIDではなく,GetProcessIdです。
> また、'Case-Sensitive'の意味がいまいち分かりません。
# 「いまいち分からない」ってどういうことでしょうか。
Case-Sensitiveとは,大文字・小文字を区別する事を意味します。
Case-InsensitiveはCase-Sensitiveの対義語で,大文字・小文字を区別しない事を意味します。
YuO様、投稿ありがとうございます。
前回のレスに書いていませんでした。GetProcessIdで実行しても同じ現象なのです。'Case-Sensitive'の件ですが、「いまいち」と言う表現がよくないのであれば
申し訳ございません。m(_ _)m
大文字・小文字を区別を指しているとは思わず、丁寧な(別の)表現があると思い
勘違いしていました。本題に戻り、英語版のホームページとか見たのですが、
(実際は英語版がほとんどですけど)同じコードなのにうまくいかない。
あ,前提条件読み飛ばしていました。
> OS:Windows2000
ではだめです。
> # Required: Windows XP SP1 or later
なので。
となると,
FindExecutable http://msdn.microsoft.com/en-us/library/bb776419.aspx
で実行ファイルを探して,そのファイル名に開きたいファイルを引数として追加した後
CreateProcess http://msdn.microsoft.com/en-us/library/ms682425.aspx
でしょうか。
ただし,関連付けの引数指定を全く無視することになるので,注意が必要です。
# CreateProcessの莫大な情報が不要なら,Shell関数でよい気もします。
YuO様、いつもありがとうございます。
FindExecutable関数は分かりました。ダブルクリックでファイルで開いたままか確認するのに役立ちます。
関数の3番目の引数lpResultにファイルに関連付けしているアプリケーションファイル(フルパス)を設定しますが、
当初の質問に戻りますが、このアプリケーションファイルと開きたいファイルをCreateProcess関数にどのように設定するのか分からないのです。
何かいい方法があれば教えてください。
また、私がいまやりたいことは、MSHFlexGridにタイトルとファイル名の一覧表を表示し、ファイル名をダブルクリックすると
そのファイルを開き、プログラム終了時に放置されたものを閉じたいのです。開くのは
Shell関数、ShellExecuteEX関数及びCreateProcess関数でもいいのですが、閉じるときに開いたファイルが放置]
されているか確認し、放置状態であればそれを閉じたいのです。これを実現するにはどの関数を使うか検討しています。
色々ご迷惑をお掛けしているとは思いますが、よろしくお願いします。
> このアプリケーションファイルと開きたいファイルをCreateProcess関数にどのように設定するのか分からないのです。
ref) http://msdn.microsoft.com/en-us/library/ms682425.aspx
・lpApplicationNameをvbNullStringに設定する
・lpCommandLineにコマンドラインをそのままいれる
でよいです。
コマンドプロンプトから起動する時と同じコマンドラインになります。
ex) C:\Windows\NotePad.exe test.txt
> プログラム終了時に放置されたものを閉じたいのです。
原則的に無謀です。
特定のアプリケーション相手である事が確定しているのであれば不可能ではないですが。
その場合は,そのアプリケーションに特化した方法を採る方がよいです。
OfficeなどではCOMによるオートメーションが使えます。
AutoCADもできるようですので,そちらによる制御ができないかを調べた方がよいでしょう。
こんにちは。
>また、私がいまやりたいことは、MSHFlexGridにタイトルとファイル名の
>一覧表を表示し、ファイル名をダブルクリックすると
>そのファイルを開き、プログラム終了時に放置されたものを閉じたいのです
APIの宣言は調べて下さい。
Command1_Clickで開き
Command2_Clickで閉じます。
又、フォームのクローズでも閉じるチェックをしています。
フォームモジュールに
Option Explicit
Private pID As Long
Private Sub Command1_Click()
Dim strEXE As String
Dim strData As String
strEXE = "C:\Program Files\ACAD LT 2000\aclt.exe "
strData = "D:\TEST.DWG"
pID = Shell(strEXE & strData, vbNormalFocus)
' ' 起動待ち
On Error Resume Next
Do
DoEvents
Err.Clear
AppActivate pID
Loop Until Err.Number = 0
On Error GoTo 0
End Sub
Private Sub Command2_Click()
Dim lngHdl As Long
Dim lngExitCode As Long
Dim lngRtn As Long
If pID = 0 Then Exit Sub
lnghWnd = 0
' CAD終了時にウィンドウがあるかチェック(無くてもよさそうですが一応
lngRtn = EnumWindows(AddressOf EnumWinProc, pID)
If lnghWnd = 0 Then Exit Sub
lngHdl = OpenProcess(PROCESS_QUERY_INFORMATION Or _
PROCESS_TERMINATE, 0, pID)
lngRtn = GetExitCodeProcess(lngHdl, lngExitCode)
lngRtn = TerminateProcess(lngHdl, lngExitCode)
lngRtn = CloseHandle(lngHdl)
pID = 0
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Command2_Click
End Sub
標準モジュールに
Public lnghWnd As Long
Public Function EnumWinProc(ByVal hWnd As Long, lParam As Long) As Boolean
Dim lngThreadId As Long
Dim lngProcesID As Long
lngThreadId = GetWindowThreadProcessId(hWnd, lngProcesID)
If lParam = lngProcesID Then
lnghWnd = hWnd
EnumWinProc = False
Exit Function
End If
EnumPass:
EnumWinProc = True
End Function
YuO様及びYK様、投稿ありがとうございます。
YK様のサンプルを実行したらうまくいきました。自分のイメージどうりにならました。どうもありがとうございます。
これで解決とします。今回のことで色々勉強になりました。ありがとうございます。