VB6でExcelを制御するには?

解決


あんぶー  2004-04-20 11:52:18  No: 112891  IP: [192.*.*.*]

はじめまして.[VB6.0 Windows2000pro office2002]
VBで作成したメニュー画面より,コモンダイアログを表示し,
そこでユーザが選択したエクセルファイルを読み取り専用としてオープンしたいと思っています.
VB側としては,エクセルファイルが立ち上がっている状態の場合は,メニュー画面をいじることは出来ないように死体のです.(複数のエクセルファイルを起動させないために)

実際に,エクセルオブジェクトを作成し,エクセルファイルを立ち上げることが出来ましたが,VBとオープンされたエクセルファイルと別々に動作してしまいます.

ご存知の方がいらっしゃいましたらぜひご教授願います.

編集 削除
ハナクソース  2004-04-20 13:27:45  No: 112892  IP: [192.*.*.*]

単純にExcelが起動されているかどうか であれば、APIを使用し、現在実行中のプロセスを調べて、Excel.exeがあればそのメニューをいじらない  というロジックにすればできるのではないでしょうか??

起動されているExcelのファイル名までチェックしたいのであれば、VBでExcelを起動した時にファイル名を覚えておいて、それでチェックするとか。
でもコレだと、VB以外から起動したExcelファイルについてはダメですけどね(^^;)

ほんとは、Excel起動の有無+起動されているファイル名  まで取得してやるのが一番なんでしょうけど…ちょっと私にはわからないです。すみませんm(_ _)m

編集 削除
あんぶー  2004-04-20 15:51:05  No: 112893  IP: [192.*.*.*]

ハナクソース様
早速の回答ありがとうございます.

> 起動されているExcelのファイル名までチェックしたいのであれば、VBでExcelを起動した時にファイル名を覚えておいて、それでチェックするとか。
> でもコレだと、VB以外から起動したExcelファイルについてはダメですけどね(^^;)
ということで,VB側でオープンさせたエクセルに対してウィンドウハンドラを取得しその値を保持するようにしてみましたが,思うように処理が出来ませんでした.
(技術の無さです)
また,エクセルオブジェクトに対してユーザが何らかのイベントを起こした際に
VB側から取得できるでしょうか?

よろしくお願いします.

編集 削除
あんぶー  2004-04-20 16:51:20  No: 112894  IP: [192.*.*.*]

たびたびすみません.

以下のようにエクセルファイルの制御を行ってみました.
読みにくいソースかもしれませんがよろしくお願いします
他に良い方法がございましたら,ご教授お願いします.

メニュー画面(menu.frm)
'------------------------------------------------------
'実行ボタンが押下された際の処理
'------------------------------------------------------
private sub cmdActionMenu_click()
・・・・
 ' コモンダイアログを表示
 dlgCmnDialog.ShowOpen
        
 ' 選択されたファイル名を取得
 If dlgCmnDialog.FileName = "" Then ' ファイルが選択されていない場合は終了
  Exit Sub
 End If
        
 cmdActionMenu.Enabled = False      ' 「実行」ボタンを非表示
 bSelectFile = dlgCmnDialog.FileName
 ' ファイルオープン
 Call FileReadForExcel(bSelectFile, bCaption)
        
 ' エクセルアプリケーションが終了するまで待機
 Call WatchExcelHandle(bCaption)
        
 dlgCmnDialog.FileName = ""          ' ファイル名の初期化
 cmdActionMenu.Enabled = True        ' 「実行」ボタンを非表示
Exit Sub

private Sub FileReadForExcel(ByVal pSelectFile As String, ByRef pCaptionTitle As String)
    Dim xlApp   As Excel.Application
    Dim xlBook  As Excel.Workbook
    Dim xlSheet As Excel.Worksheet

On Error GoTo ErrFileReadForExcel
    Set xlApp = CreateObject("Excel.Application")
    Set xlBook = xlApp.Workbooks.Open(pSelectFile) 
    Set xlSheet = xlBook.Worksheets(1)             

    pCaptionTitle = xlApp.Caption ' キャプション名取得
    xlSheet.Application.Visible = True     

    Set xlSheet = Nothing        ' オブジェクトの解放\
    Set xlBook = Nothing
    Set xlApp = Nothing

ErrFileReadForExcel:
    If Err.Number <> 0 Then
        Call MsgBox("エラーが発生しました。", vbCritical, App.Title)
    End If
Exit Sub

End Sub

private Sub WatchExcelHandle(ByVal pCaptionTitle As String)
    Dim wkHwnd As Long
    
    '参考キャプション名を与えてハンドルを取得する
    wkHwnd = FindWindow(vbNullString, pCaptionTitle)
    
    ' エクセルファイルが起動中の場合
    If wkHwnd <> 0 Then
        Sleep (2000)         ' いったんプログラムを停止
        ' 再度このプロシージャを呼ぶ
        Call WatchExcelHandle(pCaptionTitle)
    End If
End Sub

編集 削除
ハナクソース  2004-04-21 10:09:33  No: 112895  IP: [192.*.*.*]

遅くなりましたm(_ _)m

あんぶーさんのソースを参考に私の環境で実行してみましたが、動作しました。
(あるウィンドウのハンドルを取得し、そのウィンドウが閉じられるまではループしてました)

>思うように処理が出来ませんでした.
↑↑↑具体的に、意図する動きと現状の動きはどのようなものでしょうか?↑↑↑

とりあえず、ステップ実行してみてはどうでしょうか??

それと、WatchExcelHandle内でウィンドウハンドルの戻り値を聞いて再度自分自身(WatchExcelHandle)をCALLしていますが、特別な理由がないのであれば、ロジック的には以下のようにしたほうが望ましいのではないかと思います。


①WatchExcelHandleをFuncitionにする。(戻り値:ウィンドウハンドル)
②cmdActionMenu_click()プロシージャでウィンドウハンドルの戻り値を聞いて、待ち合わせ or 処理続行の判断をする。 

↓↓こんな感じ↓↓
wkHwnd =WatchExcelHandle
Do While(wkHwnd <>0)
    Sleep(2000)
    wkHwnd =WatchExcelHandle
Loop 

おそらくここが問題ではないと思いますし、まぁ好みの問題(^^;)な気もしますので、よかったら参考程度に。

編集 削除
あんぶー  2004-04-21 16:30:01  No: 112896  IP: [192.*.*.*]

ハナクソースさまご確認ありがとうございます.

>>思うように処理が出来ませんでした.(2004/04/20(火) 13:27:45)
>↑↑↑具体的に、意図する動きと現状の動きはどのようなものでしょうか?↑↑↑
というのは,
このアプリケーションを実行している際は,他のエクセルが起動しない.
画面を移動させると残像(?)が残ってしまう.
といった点です.

結局Shell関数を使用して以下のように修正しようと思います.(すみません)
同じような起動方法なのに,エクセルの立ち上がり状態が違うのはなぜなのでしょうか?

・・・とかいた時点で気づいたのですが,ウィンドウハンドラの解放って結構重要なことですよね?

Public Function FileReadForExcel(ByVal pSelectFile As String, ByRef pCaptionTitle As String) As Boolean
  Dim xlApp    As Excel.Application
  Dim xlPath   As String
  Dim wkProcID As Long
  Dim wkHandle As Long
  Dim wkStatus As Long
  Dim Buffer   As String

On Error GoTo ErrFileReadForExcel
  FileReadForExcel = False
    
  Set xlApp = CreateObject("Excel.Application") ' オブジェクトの作成
  pCaptionTitle = xlApp.Caption
  xlPath = xlApp.Path & "\" & m_Excel_Name      ' Excel実行ファイル名取得
  Set xlApp = Nothing                           ' オブジェクトの解放

  xlPath = xlPath & " " & pSelectFile           ' 起動させたいファイルを追加
  wkProcID = Shell(xlPath, vbNormalFocus)       ' プロセス実行,ID取得
  If wkProcID = 0 Then
    ' IDが取得できない
    Call CmLog(g_SystemName, "modViewr(FileReadForExcel)", _
    "以下のコマンドが実行できませんでした。" & xlPath, _
    "", CmGetFilePath(g_LogDir, g_LogFileName))
    Exit Function
  End If

  ' ハンドル取得
  wkHandle = OpenProcess(SYNCHRONIZE, True, wkProcID)
  If wkHandle = Null Then
    Buffer = Space(300)
    FormatMessage FORMAT_MESSAGE_FROM_SYSTEM, ByVal 0&, GetLastError(), LANG_NEUTRAL, Buffer, 300, ByVal 0&
        Buffer = Left$(Buffer, InStr(1, Buffer, vbNullChar & vbNullChar) - 1)
    Call MsgBox("エラーが発生しました。Err:" & Buffer, vbCritical, App.Title)
  End If
    
  ' プロセス待機
  wkStatus = WaitForSingleObject(wkHandle, INFINITE)
  If wkStatus <> WAIT_OBJECT_0 Then

    Buffer = Space(300)
    FormatMessage FORMAT_MESSAGE_FROM_SYSTEM, ByVal 0&, GetLastError(), LANG_NEUTRAL, Buffer, 300, ByVal 0&
    Buffer = Left$(Buffer, InStr(1, Buffer, vbNullChar & vbNullChar) - 1)
    Call MsgBox("エラーが発生しました。Err:" & Buffer, vbCritical, App.Title)
    End If
    
    ' ハンドルの解放
    If wkHandle <> 0 Then CloseHandle (wkHandle)
    wkHandle = 0
    
    FileReadForExcel = True
    Exit Function

ErrFileReadForExcel:
    If Err.Number <> 0 Then
        Call MsgBox("エラーが発生しました。Err:" & Err.Description, vbCritical, App.Title)
    End If
    Exit Function

End Function

最後に,ハナクソースさま,回答どうもありがとうございました.
また何か行き詰まったときはよろしくお願いします.

編集 削除