[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『別プロセスでブックを開きたい(ネットワーク越し・PASS付き)』(ろでます)
こんにちわ、ろでますです。
いつもお世話になっております。
この度の質問なんですが、ちょっとややこしいので箇条書きにさせていただきます。
1.エクセルのブックを別プロセスのエクセルで開きたい
2.A開きたいファイルはネットワークの先にある
3.ファイルにはパスワードがついてある
です。
1.をやりたい目的として、別プロセスで起動し、1つ目のプロセスで起動したエクセルのブックを画面左上に小ウィンドとして常に最前面にして固定。別プロセスで開いたエクセルファイルは全画面で開き、1つ目のプロセスで開いたエクセルの背面に起動したいという意図です。
2.は書いてある通りなのですが、Shellを使って開こうとしたのですが、どうもエラーが出てしまいます。
sub main()
File=\\192.168.0.1\book1.xlsx call shell(File) end sub
3.も書いた通りなのですが、ブックにPASS付きの場合、Shellで何らかの方法で開ける場合に、PASSがついている場合は引数に何か指定をすればPASS付きブックを開けるのでしょうか?
もし、単にWorkbooks.openだけで対応できるのでしたら、非常にちんぷんかんぷんな質問で申し訳ございません。
どうもいろいろ調べたのですが、やり方が見つからなくて、こちらでご質問させていただきました。
何卒ご教授のほどをよろしくお願い申し上げます。
< 使用 Excel:Excel2010、使用 OS:Windows7 >
こちらをご覧いただければ、よろしいかと思います。
(パオ〜〜ン) 2015/02/16(月) 13:27
shellでは関連付けには対応していない(.exe形式のファイルを開く)ので Shell "excel.exe " & File のようにしてはどうか?
パスワードは自分で入力することになるが。
追記 パス名にスペースなどが入る場合を考慮すると Shell "excel.exe """ & File & """" のほうがいいかもすれない。 (ねむねむ) 2015/02/16(月) 13:34
掲示板の方拝見させていただきました。
大変失礼なご回答可とは思いますがご容赦ください。
こちらの掲示板の内容では、あくまで一つのプロセスで実施してしまうため。私が1で書いた
「1つ目のプロセスで起動したエクセルのブックを画面左上に小ウィンドとして常に最前面にして固定。別プロセスで開いたエクセルファイルは全画面で開き、1つ目のプロセスで開いたエクセルの背面に起動したい」
ができないと思います。
一つのプロセスで開いてしまった場合は、エクセルのウィンド一つに複数のブックが開かれてしまうためです。
コメントを頂いて、誠に申し訳ないのですが、この方法だと対処できないのでは・・・と思ってしまいます。
(ろでます) 2015/02/16(月) 13:58
小ウィンドで固定を取るか、パスの手入力自動化を取るかの両天秤にならざるを得ないということですね。
かなり困難(というか、仕様上不可能)なようですね・・・
(ろでます) 2015/02/16(月) 14:01
Sub Test() Dim excelApp As Excel.Application Dim File As String Set excelApp = CreateObject("Excel.Application") File = "\\192.168.0.1\book1.xlsx" With excelApp .Workbooks.Open File, , , , "パスワード" .Visible = True End With Set excelApp = Nothing
End Sub ではどうだろうか? 「パスワード」のところを実際のパスワードにしてくれ。
追記 全画面表示を忘れていた。 > .Visible = True の次に .DisplayFullScreen = True と入れてくれ。
(ねむねむ) 2015/02/16(月) 14:18
ただ、自分なりになぜ動作するのかをネットで色々調べていたので、遅くなってしまいました。
http://www.accessclub.jp/vbakaisetu/50.html
を見ると、なぜねむねむ様のマクロで別プロセスのワークブックが開くのかが、おおよそ理解できました。(5割くらいです(^^;)
しかしながら、この状態だと、私のやりたかった
「1つ目のプロセスで起動したエクセルのブックを画面左上に小ウィンドとして常に最前面にして固定」
ができず、背面に移動してしまいます。
教えてくんになってしまい誠に申し訳ございませんが、何か良い解決方法がございましたら、ご教授願えませんでしょうか。
ちなみに、素人考えで、
ThisWorkbook.activate
ではだめでした・・・
(ろでます) 2015/02/16(月) 16:05
すまない、すでに前面に表示するのはできているのだと思っていた。
下記を参考にしてできないだろうか? http://www.vbalab.net/vbaqa/c-board.cgi?cmd=ntr;tree=47448;id=excel
もし、上記がダメな場合はアイデアだけだが、一つのインスタンス(プロセス)で開いてExcel本体は全画面表示で それぞれのブックをウィンドウ表示させてはどうだろうか? (ねむねむ) 2015/02/16(月) 16:20
Private Declare Function SetWindowPos Lib "user32" _ (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, _ ByVal x As Long, ByVal y As Long, ByVal cx As Long, _ ByVal cy As Long, ByVal wFlags As Long) As Long Const HWND_TOPMOST = -1
Sub Test() Dim excelApp As Excel.Application Dim File As String
Set excelApp = CreateObject("Excel.Application") File = "\\192.168.0.1\book1.xlsx" With excelApp .Workbooks.Open File, , , , "パスワード" .Visible = True SetWindowPos .hwnd, HWND_TOPMOST, 0, 0, 640, 400, 0 End With Set excelApp = Nothing End Sub (???) 2015/02/16(月) 16:31
お二人から頂きましたコメントで、ほぼ完璧に対処できました。
Private Declare Function SetWindowPos Lib "user32" _ (ByVal hwnd As Long, ByVal hWndInsertAfter As Long, _ ByVal x As Long, ByVal y As Long, ByVal cx As Long, _ ByVal cy As Long, ByVal wFlags As Long) As Long Const HWND_TOPMOST = -1
ここを理解するのが滅茶苦茶難しそうですが(^^;
最後に、贅沢を一つだけお願いできませんでしょうか。(ホントにすいません)
このエクセルのブックを開いた際に、自動的に左上最前面に移動するようにしようとして、ThisWorkbok内に
頂いた例(ねむねむさんの例で)
Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Declare Function SetWindowPos Lib "user32" (ByVal hWnd As Long, _
ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, _
ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Dim MyFlg As Boolean
Const TUNENI_TEMAE_SET = -1 '常に手前にセット
Const KAIJYO = -2 '解除
Const HYOUZI_SURU = &H40
Const NO_SIZE = &H1
Const NO_MOVE = &H2
Private Sub Workbook_Open()
Dim hWnd As Long, Ret As Long Dim Ans As Integer
hWnd = FindWindow("XLMAIN", Application.Caption) If MyFlg Then Ans = MsgBox("常に手前表示を解除しますか", 36) If Ans = 6 Then Ret = SetWindowPos(hWnd, KAIJYO, 0, 0, 0, 0, _ HYOUZI_SURU Or NO_MOVE Or NO_SIZE) MyFlg = False End If Else Ans = MsgBox("常に手前に表示しますか", 36) If Ans = 6 Then Ret = SetWindowPos(hWnd, TUNENI_TEMAE_SET, 0, _ 0, 0, 0, HYOUZI_SURU Or NO_MOVE Or NO_SIZE) MyFlg = True End If End If End Sub と記載したのですが、上手く動きません。(まったくウィンド移動等もありません)
ブックを開いた時点で動作する方法はありますでしょうか?
本当に教えてばかりで申し訳ございません。
(ろでます) 2015/02/16(月) 17:05
サイズはデフォルトでいい。左上に移動と最前面だけでいい。他Excelではなく、自Bookでいい、ということならば、以下。
Private Declare Function SetWindowPos Lib "USER32" _ (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, _ ByVal x As Long, ByVal y As Long, ByVal cx As Long, _ ByVal cy As Long, ByVal wFlags As Long) As Long Const HWND_TOPMOST = -1 Const NO_SIZE = &H1
Private Sub Workbook_Open() SetWindowPos Application.hWnd, HWND_TOPMOST, 0, 0, 0, 0, NO_SIZE End Sub (???) 2015/02/16(月) 17:28
返信遅れて申し訳ございません。
???さんのコメントいただいた内容の理解と、あと一つ昨日考えていた・・・もしかして・・・という罠にはまってしまいました。
罠というのは、当然エクセルのプロセスを2つ起動するのだから、例えば1つ目のプロセスの方で起動しているマクロで、2つ目に起動したプロセス側に対してマクロの命令を送れないという罠です。
例えるなら、1つ目のプロセスで開いたエクセルのマクロ内に、2つ目のプロセス内にあるワークブックをアクティブにして、操作しようと思ってもできませんでした。
自力での解決を今までいろいろ調べたり試していたのですが、やはり私のスキルでは困難でした・・・。
もしかしたら、既存のマクロを
ねむねむさんから頂いたマクロに似せて
Sub Test() Dim excelApp As Excel.Application Dim File As String Set excelApp = CreateObject("Excel.Application") File = "\\192.168.0.1\book1.xlsx" With excelApp .Workbooks.Open File, , , , "パスワード" .Visible = True End With Set excelApp = Nothing
End Sub の様にWithブロックで括り付けて、内部に、2つ目のプロセスで動かしたいマクロを書けばと・・・素人考えでやってみたところ、どうもうまくいきそうだ・・・というのが今の段階です。
しかし、この方法だと、今あるマクロ全てをWithブロック内に格納する必要がある為、かなり修正等に時間がかかってしまいそうです。
他に
「こんな方法がありますよ」
というアドバイス等ございましたら、何卒ご教授のほどをよろしくお願い申し上げます。
(ろでます) 2015/02/17(火) 14:10
Withにしているのは
excelApp.Workbooks.Open File, , , , "パスワード" excelApp.Visible = True
といちいち「excelApp」を頭に着けずに済むためにWithを付けている。
処理としては >Set excelApp = CreateObject("Excel.Application") で、新しいプロセスでExcelを開いてexcelAppに代入、 >Set excelApp = Nothing で、excelAppと新しく開いたExcelとの関連を解除しているのでこの二つの間でexcelAppを頭に着けて操作すればよいことになる。 一つ一つ頭に「excalApp」を付けるか(もっと短い名前にしてしまう方法もあるが)Withで省略可能にするか組み方も考慮して決めてはどうだろうか。 (ねむねむ) 2015/02/17(火) 14:33
私の方でも、さっきまで検証していて、
よく考えるとオブジェクト化しているんだから、もっと単純に
Dim Ap As Excel.Application
Set Ap = CreateObject("Excel.Application") Ap.Workbooks.Open BillSePath, , , , "6402" Ap.Visible = True Ap.DisplayFullScreen = True
・
・
・
と、マクロコードの頭に「AP.」を付ければ、住むのかなと思って検証していました。
結果的にはうまくいきそうです。
ところでと言ってはなんなのですが(実は深刻)で、これと同じ方法で、ファイルを開く部分だけを別の標準モジュールに分けて、ユーザー定義関数として動かす必要が出てきました。
というのも、ある部門ではファイルアクセスにパスワードを手入力させ、ある部門では自動・・・といった要求仕様が出てきたためです。
ためしに以下のようなマクロを組んでみました。
Module1内
Sub Sample
Dim Ap As Excel.Application Dim Flag As Boolean
Flag = Application.Run("FileOpen", BillSePath) If Flag = False Then Exit Sub End If End Sub
Module2内
Function FileOpen(ByVal OPN) As Boolean
On Error Resume Next Ap.Workbooks.Open FileName:=OPN, Password:="xxxx" 'ここでPASSを有効するか無効にするかを設定し、モジュールのエクスポートで部門ごとに分ける。 If ActiveWorkbook.ReadOnly = True Then MsgBox "他のユーザーが既に開いています" & vbCrLf & "読み込み専用、または通知を待ちます" Else FileOpen = False Exit Function End If Err.Clear On Error GoTo 0
FileOpen = True
End Function
APオブジェクトがユーザー定義関数FileOpenにも引き継がれるのかと思っていましたが、これでは、ファイルを開くどころか、うんともすんとも言いませんでした。
この場合、オブジェクトでAPを渡してファイルを開かせるにはどのようにすればよろしいでしょうか?
本当に、厚かましいお伺いばかりで申し訳ございませんが、何卒よろしくいお願い申し上げます。
(ろでます) 2015/02/17(火) 14:59
Option Explicit を使って確認してみてはどうでしょうか。 Ap はスコープを外れています。 (Mook) 2015/02/17(火) 15:02
試してみました。
おっしゃる通り、ユーザー定義関数内で、
「Option Explicit」
を付けると、
>Ap.Workbooks.Open FileName:=OPN, Password:="xxxx"
のところで
「変数が定義されていません」(AP)
のエラーが出ました。
ということは、オブジェクトが渡せていないということになりますね(多分・・・)
モジュール間でオブジェクトを渡す方法を考えないといけないようですね・・・。
(ろでます) 2015/02/17(火) 15:12
Module1内
Option Explicit
Sub Sample
Dim Ap As Excel.Application Dim Flag As Boolean
Set Ap = CreateObject("Excel.Application")
Flag = AP.Application.Run("FileOpen", BillSePath) If Flag = False Then Exit Sub End If End Sub Module2内
Option Explicit
Function FileOpen(ByVal OPN) As Boolean
On Error Resume Next Workbooks.Open FileName:=OPN, Password:="xxxx" 'ここでPASSを有効するか無効にするかを設定し、モジュールのエクスポートで部門ごとに分ける。 If ActiveWorkbook.ReadOnly = True Then MsgBox "他のユーザーが既に開いています" & vbCrLf & "読み込み専用、または通知を待ちます" Else FileOpen = False Exit Function End If Err.Clear On Error GoTo 0
FileOpen = True End Function
こうすると、
「実行時エラー1004」
「マクロFileOpenを実行できません・・・」
のエラーが出るようになりました。
なんだかうまくいきそうでうまくいってないような気が・・・
(ろでます) 2015/02/17(火) 15:33
いまいちよい方法ともいえないが…
Module1の先頭(プロシージャの外)で
Public Ap As Excel.Application として、パブリック変数として指定。
Module1以外で使う場合は Module1.Ap.Workbooks.Open FileName:=OPN, Password:="xxxx" とApの前にモジュール名を付けてはどうだろうか? (ねむねむ) 2015/02/17(火) 15:35
すいません、せっかくコメントいただきましたが、自己解決しました。
以下のようにしたらあっさり行きました。
Module1内
Option Explicit
Sub Sample
Dim Ap As Excel.Application Dim Flag As Boolean
Set Ap = CreateObject("Excel.Application")
Flag = AP.Application.Run("FileOpen", BillSePath,AP) If Flag = False Then Exit Sub End If End Sub
Module2内
Option Explicit
Function FileOpen(ByVal OPN, ByVal AP As Excel.Application)
On Error Resume Next AP.Workbooks.Open FileName:=OPN, Password:="6402" If OPN.ReadOnly = True Then MsgBox "他のユーザーが既に開いています" & vbCrLf & "読み込み専用、または通知を待ちます" Else FileOpen = False Exit Function End If Err.Clear On Error GoTo 0
FileOpen = True
End Function
で解決しました!
すいません、お手数ばかりおかけしまして申し訳ありませんでした。
(ろでます) 2015/02/17(火) 16:00
Module1内
Option Explicit
Sub Sample
Dim Ap As Excel.Application Dim Flag As Boolean
Set Ap = CreateObject("Excel.Application")
Flag = AP.Application.Run("FileOpen", BillSePath,AP) If Flag = False Then Exit Sub End If End Sub Module2内
Option Explicit
Function FileOpen(ByVal OPN, ByVal AP As Excel.Application)
On Error Resume Next AP.Workbooks(Dir(OPN)).Activate 'OPNの2重開き防止用 If Err > 1 Then AP.Workbooks.Open FileName:=OPN, Password:="xxxx" If OPN.ReadOnly = True Then MsgBox "他のユーザーが既に開いています" & vbCrLf & "読み込み専用、または通知を待ちます" Else FileOpen = False Exit Function End If Err.Clear End If On Error GoTo 0
FileOpen = True
End Function
としても、
> AP.Workbooks(Dir(OPN)).Activate 'OPNの2重開き防止用
の所がうまく働かず、結果エラー処理が「Err>1」となって2重開きになってしまいます。
ためしに
Option Explicit
Function FileOpen(ByVal OPN, ByVal AP As Excel.Application)
Dim OPNDir
'On Error Resume Next AP.Workbooks(Dir(OPN)).Activate If Err > 1 Then AP.Workbooks.Open FileName:=OPN, Password:="xxxx" If OPN.ReadOnly = True Then MsgBox "他のユーザーが既に開いています" & vbCrLf & "読み込み専用、または通知を待ちます" Else FileOpen = False Exit Function End If 'Err.Clear End If 'On Error GoTo 0
FileOpen = True
End Function
とエラー処理部分をコメントアウトしてみると
>AP.Workbooks(Dir(OPN)).Activate
のところで、「インデックスが有効範囲にありません」
のおなじみのエラーが出てしまいます。
APは2つ目のプロセスのエクセル自身のオブジェクトで、そのワークブックオブジェクトをアクティブにしようとしているのだから・・・うまくいくと思ったのですが、なぜだか上手くいかない次第です。
今色々自分で試してはいるのですが・・・。
度々で誠に申し訳ございません。
何卒アドバイスのほどをお願い申し上げます。
(ろでます) 2015/02/17(火) 16:51
これだけ見てたら、Set APした後に、一度もブックを開いていないから、100%エラーになると思いますが。 BillSePathってどこから出てきた変数?
あと察するにOPNはString型だけど >OPN.ReadOnly こんなプロパティないでしょ。
こういうテストしてみてください。 エラーはA-1だけしか出ないはずです。
Sub test() Dim ap As Excel.Application Dim fn As String fn = "C:\エクセルの学校\ろでます\a.xlsm" Set ap = CreateObject("Excel.Application") testA ap, 1, fn ap.Workbooks.Open (fn) testA ap, 2, fn ap.Quit End Sub Function testA(ByVal ap As Excel.Application, ByVal i As Long, ByVal fn As String) Dim wb As Workbook On Error Resume Next Set wb = ap.Workbooks(Dir(fn)) If Err > 0 Then MsgBox "エラー発生 A-" & i Err.Clear On Error GoTo 0 End Function (稲葉) 2015/02/17(火) 17:20
すいません、
>OPN.ReadOnly
>こんなプロパティないでしょ。
この点はおっしゃる通りです。
一度Workbookオブジェクトにするように変更しました。
ただ、いただきましたマクロだと、最後の
「ap.Quit」
で
「C:\エクセルの学校\ろでます\a.xlsm」
を閉じる命令を出しています。
ここは、閉じずに利用者が開いたエクセルファイルを編集できるようにと考えています。
その上で以下のようにしてみました。
Sub test() Dim ap As Excel.Application Dim fn As String fn = "C:\エクセルの学校\ろでます\a.xlsm" Set ap = CreateObject("Excel.Application") testA ap, 1, fn ap.Workbooks.Open (fn) testA ap, 2, fn ap.Visible = True ap.Application.WindowState = xlMaximized 'ap.Quit ここで開いたファイルを閉じない End Sub Function testA(ByVal ap As Excel.Application, ByVal i As Long, ByVal fn As String) Dim wb As Workbook On Error Resume Next Set wb = ap.Workbooks(Dir(fn)) If Err > 0 Then MsgBox "エラー発生 A-" & i Err.Clear On Error GoTo 0 End Function
この状態で、もう一度マクロを回すと、どんどんと読み取り専用で
「ろでます\a.xlsm」
が開かれていってしまいます。
私のやりたいことは、この多重に開いていくのを防止して、一度開いているファイルについて、もう一度マクロを回すと、再度そのファイルが開かれず、開いている「ろでます\a.xlsm」がアクティブになることをやりたいと考えています。
本当に度々で申し訳ございませんが、よきアドバイス等ございましたら何卒よろしくお願い申し上げます。
(ろでます) 2015/02/18(水) 10:51
テストだって言ってるでしょうが!!!!!!!!!!!!!!!!!!!!!
別プロセスで開いたエクセルを見たいなら、ねむねむさんが提案している通り、 Publicで宣言するしかないと思います。
ただし、コードがこけたりすると、変数に保持されていたオブジェクトは消えるので もう一度探しなおす必要があります。
今のレベルで実装しても、不具合や改定があった時に対応できないと思いますので 今回の件は諦めたほうがいいと思います。 (稲葉) 2015/02/18(水) 11:52
Dim ap As Excel.Application
Sub test() Dim fn As String fn = "C:\エクセルの学校\ろでます\a.xlsm" testA 1, fn testA 2, fn End Sub
Function testA(ByVal i As Long, ByVal fn As String) Dim wb As Workbook Dim F1 As Integer Dim iErr As Long
F1 = FreeFile
On Error Resume Next Open fn For Append As #F1 iErr = Err.Number Close #F1 On Error GoTo 0
If iErr = 0 Then Set ap = CreateObject("Excel.Application") ap.Workbooks.Open (fn) Else ap.Workbooks(Dir(fn)).Activate End If
ap.Visible = True ap.Application.WindowState = xlMaximized End Function
ただし、このマクロ以外でa.xlsmを開いておいた場合、apには何の情報も入っていないので、エラーになります。
(???) 2015/02/18(水) 12:01
まずは、???様にいただいたマクロを理解して、何とか頑張ってみようと思います。
それでも私の手におえないようであれば、私のスキル不足です。
その場合は、稲葉様のおっしゃる通り、今回の件はあきらめた方がよろしいかもしれません。
どうも、お手数ばかりおかけして申し訳ございません。
(ろでます) 2015/02/18(水) 14:52
On Error Resume Next Open fn For Append As #F1 iErr = Err.Number Close #F1 On Error GoTo 0
Openしてから何もせずにCloseしているのは何故か?
これは、既にa.xlsmが開かれている場合、ファイルとしては排他がかかるため、変更できなくなっている事を調べています。
開いていなければエラーにはならず、既に開いていればopenエラーになる訳ですね。これで重複openを抑止できます。
あとは、a.xlsmを開いたExcelオブジェクトはapに格納されているので、このブックを閉じない間(apオブジェクトを解放しない間)はa.xlsmを操作可能。
しかし、別途手動でa.xlsmを開いてあったり、マクロで開いたとしても、マクロ入りブックを閉じてしまうと
apオブジェクトが解放されてしまうため、再度マクロ入りブックを実行しても、a.xlsmを開いたのは他人扱いされる、という点を理解してください。
(つまり、どちらか一方を閉じてしまうと連携できなくなってしまう問題を抱えている)
次に、一般的な解決案ですが、普通はブックを2つ使わず、1つのブックで済ませます。左上ブックの代わりは、
UserFormでも使えばよろしい。これならば、ブックを閉じればフォームも同時に閉じるので、他人ブック問題が起こりません。
(???) 2015/02/18(水) 16:36
なるほど、私が今必死に調べていたところでした。
やはり、自分自身がやりたいことは、かなり無理をしていることも理解できました。
>次に、一般的な解決案ですが、普通はブックを2つ使わず、1つのブックで済ませます。左上ブックの代わりは、
>UserFormでも使えばよろしい。これならば、ブックを閉じればフォームも同時に閉じるので、他人ブック問題が起こりません。
その方法は、私の知識不足でした、すいません。
これから、UserFormを勉強して、その方法を試みてみたいと思います。
(ろでます) 2015/02/18(水) 16:42
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.