[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『エラー処理について』(やわら)
お世話になっております。
エラー処理が分からず、質問させてください。
元々あるExeにbat経由で引数を渡して実行させるコードがあります。 (元コードは別人が書いたもので、改変中)
〜前略〜 'Make Batch File BatchFile = "make_wave.bat" TxtFile = "raw2wave_param.txt" Open BatchFile For Output As #1 Print #1, Cells(5, 4).Value; " "; Print #1, Cells(6, 4).Value; " "; Print #1, CsvFile; " "; Print #1, TxtFile; " "; Print #1, "" Close #1
'Execute Batch Call BatchExec(BatchFile) Kill BatchFile Kill TxtFile 〜中略〜 CsvFile = "temp.csv"
On Error Resume Next
Set WbTemp = Workbooks.Open(Filename:=CsvFile)
If Err.Number <> 0 Then MsgBox "Pathかファイル名のどちらかが間違っています" Set WbTemp = Nothing Err.Clear End End If 〜後略〜
D5はExe名、D6はD2(パス)とD3(ファイル名)を合体させたものが記入されていて D6のフルパスが間違っているとワークブックオープン時にエラーを吐きます。
一回エラーが出てしまうと、何かを掴んだままになっているようで 再度正しいパスに直して実行してもエラーが出たままになってしまいます。 (エクセル開きなおせば正常実行できる)
そのため、エラートラップの中にエラークリアとEndを入れて抜けたらいいのかな?と思ったのですが やはり一度エラーが起きると正しいパスでもMsgBoxが出てしまいます。 なにか認識が誤っているのでしょうか?なぜ何回もエラーが出るのかもわからず… お力添えいただければ幸いです。よろしくお願いいたします。
< 使用 Excel:Microsoft365、使用 OS:Windows10 >
開く前に 存在するか、 既に開いていないか、 を確認する では? (tkit) 2024/02/05(月) 14:50:40
> 〜中略〜 > CsvFile = "temp.csv"
そこをちゃんとしたフルパスにしたらどうですか?
(半平太) 2024/02/05(月) 15:13:20
なんか納得いかないですねぇ。
>CsvFile = "temp.csv" ~~~↑~~~~~ これをフルパスにするんですけど、やりましたか?
あと、そのフルパスが正しくなければ話になりませんけども、そこは大丈夫ですか?
(半平太) 2024/02/07(水) 13:49:01
あとこれは質問の際に私が端折ってしまったのですが
本当はCsvFile = Range("D2") & "\temp.csv"は〜前略〜のmain関数に書かれており、
かつ複数関数にわたって使用されているのでパブリックになります。
このあたりが原因でしたら申し訳ありません。
(やわら) 2024/02/07(水) 14:00:29
>エラー処理が分からず、質問させてください。
エラー処理を勘違いされていませんか?
On Error Resume Next で実行エラーを無視することが、 エラー処理ではありません。
想定される実行エラーにならないように 順を追って確認、判定し、実行エラーになる処理を しないことが望ましいです。
(tkit) 2024/02/07(水) 14:02:13
>あとこれは質問の際に私が端折ってしまったのですが
エラーの原因を探ろうと言うのに、状況説明が正確じゃなければ こちらはミスリードされるだけです。私は、ここまでとします。m(__)m
何らかの反応は不要です。
(半平太) 2024/02/07(水) 14:28:35
※jw_cad for windowsという図面作成用のソフト関係の掲示板等で
いろいろいと教えていただきながら作ったコードの
jww専用の記述でわかりやすい部分のみ削除し、
他はほとんど触らずコードを這っているので、関係ない部分も多いです。
エクセルをマクロ有効で起動してExcelが終了するまでbatファイルを待機するコードです。
visiblはExcelブックを非表示にするのに使っています。
(実際はfalseにして、excel非表示で起動し、excelの起動時の処理でユーザーフォームを起動させてます)
batファイルに記述
@if(0==1) //線幅線色変更
@echo off
wscript //nologo //e:jscript %~f0
goto:eof
@else
var BookName = "EJ線幅線色変更.xls"
with (new ActiveXObject("Scripting.FileSystemObject")) {
var BookPath = BuildPath (GetParentFolderName(WScript.ScriptFullName),BookName); } with (new ActiveXObject("Excel.Application")) { Visible = true; try { var myBook = Workbooks.Open(BookPath); } catch(e) { // ブックが存在しない場合 Visible=true; WScript.Echo(e.description + "(Error No=" + (e.number & 0xFFFF) + ")"); WScript.Quit(); } var flg = new Boolean(false); while (flg == false){ try { with (myBook) { while (true) { WScript.Sleep(100); } } } catch(e) { if( e.number == -2147417848 ) { flg = true; } } } myBook=null; } @end
同様にbatファイル→vbsファイル→excelで起動し、
excel終了まで待機させるコードは下記です。
※vbsファイルと同じフォルダにあるvbsファイルと同名のexcelを起動になっています
batファイル
@REM Excel置換2
@echo off
start /wait Excel置換2.vbs
REM #e
:END
vbsファイル
Option Explicit
Private FSO, VbsObject , VbsPath , VbsName, FolderPath, BookName, BookPath, wb, flag
Set FSO = CreateObject("Scripting.FileSystemObject")
Set VbsObject =FSO.GetFile(WScript.ScriptFullName)
VbsName = VbsObject.Name
FolderPath = VbsObject.ParentFolder
BookName = LEFT(VbsName,LEN(VbsName)-4) & ".xls"
BookPath = FolderPath & "\" & BookName
If FSO.FileExists(BookPath) then
With CreateObject("Excel.Application") .Visible = true .Workbooks.Open(BookPath) On Error resume Next Do flag = false For Each wb In .Workbooks If wb.Name = BookName Then flag = True Next If flag = true Then WScript.Sleep 500 Else Exit Do End If Loop On Error goto 0 End With Else Wscript.echo BookPath & vblf & " が存在しません。" End IF (O.M) 2024/02/08(木) 21:07:37
If FSO.FileExists(BookPath) thenで存在確認はしているのでなくても大丈夫なはずですが、
WScript.Sleepをひたすら繰り返すのでなんとなく怖くて保険的な意味合いでつけて
外せていないコードでした。
(O.M) 2024/02/08(木) 21:28:13
関係なくてもExcelが画面の後ろに隠れて困っている場合には便利だと思うので記載しておきます。
64bitのExcelのLongptrとLongLongの使い分けがわかっておらずlongのままにしている部分が多いですが、
batファイルからExcelのブックを起動するならThisWorkbookに
'★Excelを前面に表示
#If Win64 Then
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Private Declare PtrSafe Function SetWindowPos Lib "user32" _ (ByVal hWnd As LongPtr, ByVal hWndInsertAfter As LongPtr, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long #Else Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long 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 #End If
Const HWND_TOP As Long = -1 '前面に表示
Const HWND_TOPMOST As Long = -1 '常に前面に表示
Const HWND_BIHIND As Long = 1 '後面に表示
Const HWND_CANCEL As Long = -2 'キャンセル
Const SWP_NOSIZE As Long = 1
Const SWP_NOMOVE As Long = 2
Private Sub Workbook_Open()
'★Excelを前面に表示
#If Win64 Then Dim hWnd As LongPtr #Else Dim hWnd As Long #End If '最前面に表示するウィンドウのハンドルを取得(UserForm) hWnd = FindWindow("XLMAIN", vbNullString) 'ウィンドウを常に最前面に配置 Call SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE) 'ウィンドウを常に最前面に配置解除 Call SetWindowPos(hWnd, HWND_CANCEL, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE) End sub
ユーザーフォームを起動する場合はユーザーフォームに
'★ユーザーフォームを前面に表示
#If Win64 Then
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Private Declare PtrSafe Function SetWindowPos Lib "user32" _ (ByVal hWnd As LongPtr, ByVal hWndInsertAfter As LongPtr, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long #Else Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long 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 #End If
Const HWND_TOP As Long = -1 '前面に表示
Const HWND_TOPMOST As Long = -1 '常に前面に表示
Const HWND_BIHIND As Long = 1 '後面に表示
Const HWND_CANCEL As Long = -2 'キャンセル
Const SWP_NOSIZE As Long = 1
Const SWP_NOMOVE As Long = 2
'ユーザーフォーム起動時設定
Private Sub UserForm_Initialize()
'★ユーザーフォームを前面に表示
#If Win64 Then Dim hWnd As LongPtr #Else Dim hWnd As Long #End If '最前面に表示するウィンドウのハンドルを取得(UserForm) hWnd = FindWindow(vbNullString, Me.Caption) 'ウィンドウを常に最前面に配置 Call SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE) 'ウィンドウを常に最前面に配置を解除 Call SetWindowPos(hWnd, HWND_CANCEL, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE) End sub
と記載したら前面に表示されました。
(O.M) 2024/02/08(木) 22:00:23
>本当はCsvFile = Range("D2") & "\temp.csv"は〜前略〜のmain関数に書かれており、 >かつ複数関数にわたって使用されているのでパブリックになります。
↑の意味が分からないのですが、エラーが出るというのは↓ですよね?
Set WbTemp = Workbooks.Open(Filename:=CsvFile) ~~~~~~~
ステップ実行して自己検証されたときに【CsvFile】に正しいフルパスが格納されていたのでしょうか?
お気軽に↓みたいに言ってますが、ブックもシートも指定してないので正しく格納されているのか気になります。
CsvFile = Range("D2") & "\temp.csv"
(もこな2) 2024/02/09(金) 07:38:12
コードは私には難しそうですが…似たようなというのは問題解決してるのにエラーが起きるとこですかね? ちなみに、Excel画面は最小化などされないので後者にかんしては大丈夫です。
もこな2さん
もこな2さんと私の中で「正しい」フルパスの定義が合っているのかわからないため、前提からお話しさせてください。
まずエラーが出る状態は ・D2セルが存在しないパス または ・D3セルが「D3セルのパスに」存在しないファイル名 のどちらかです。
今回は、D2を存在しないパスに変更してエラーを起こす→存在するパスに変更してもエラーが起きる ことを確認しています。(c:/hogehoge を C:/hogehog にして確認みたいな感じです)
そのため、エラーが起きている状態は当然CsvFileの中身は正しいフルパスにはならないです。 ただ、存在するパスに戻したときは正しいフルパスになっています。 (やわら) 2024/02/09(金) 17:50:56
Sub 実験1() Dim フルパス As String Dim WbTemp As Workbook
フルパス = "c:\存在しないフォルダ\temp.csv" On Error GoTo エラー処理 Set WbTemp = Workbooks.Open(Filename:=フルパス)
フルパス = "c:\存在するフォルダ\temp.csv" Set WbTemp = Workbooks.Open(Filename:=フルパス)
Exit Sub
エラー処理: MsgBox "ブックを開くのに失敗しました" Err.Clear Resume Next End Sub
全体の提示がないのでわかりかねますが、開こうとしているブック(というかcsvファイル)のパスが正しくなければそりゃ開けません
(なお、フォルダを指定しない場合はカレントフォルダを指定したことになります)
トピ主のいう「存在するパスに戻した」というのがどういうことがわからないので、【CsvFile】に正しいフルパスが格納されていたのか?と聞いています。
■3
ブックを開く前にファイルの存在チェックをするなら↓のようにするとよいです。
(ほかにも手はありますが、一番お手軽だと思います)
Sub 実験用2() Dim フルパス As String
フルパス = "c:\存在しないフォルダ\temp.csv" If Dir(フルパス) = "" Then MsgBox "フォルダまたはファイルが存在しません" Else MsgBox "指定されたファイルは存在します" End If
フルパス = "c:\存在するフォルダ\temp.csv" If Dir(フルパス) = "" Then MsgBox "フォルダまたはファイルが存在しません" Else MsgBox "指定されたファイルは存在します" End If End Sub
(もこな2 ) 2024/02/09(金) 18:36:55
> 今回は、D2を存在しないパスに変更してエラーを起こす→存在するパスに変更してもエラーが起きる > ことを確認しています。(c:/hogehoge を C:/hogehog にして確認みたいな感じです)
D2に存在するパスを入れてもエラーが起きるのですね? その原因を知りたいのですね。
これは他人に尋ねてもわかりません。デバッグはご自分がするしかありません。
ご自分で ・D2には何が入っていて、 ・そのときCsvFileは何になっているのか、 ・それはどう作られたのか というのをご自分で確認するしかありません。
お調べ下さい。
(xyz) 2024/02/09(金) 19:24:19
CsvFileというのは、D2セルの値と、ファイル名とを連結しているんですか? これと CsvFile = "temp.csv" というコードとはどういう関係にありますか? CsvFile = "temp.csv" を後に実行しているなら、そのときのカレントフォルダのなかの"temp.csv"ファイルを探します。 そのときそれが無ければ当然エラーになりますよ。
そんなオチではないんですか?よく知らないけど。 (xyz) 2024/02/09(金) 19:36:59
ちょっとだけお邪魔します。
結果、本題とは関係ない「ツッコミ」になってしまいますが... (ご容赦ください ^^;) 後々ココを訪れる方に向けての注釈的内容です。
O.Mさんのコード中に出現する
> #If Win64 Then
このコンパイラ定数(計4か所)については、 ディレクティブの内側に書いてある宣言文が「PtrSafeおよびLongPtrが書けるか否か」の分岐しか要しない内容なので
#If VBA7 Then
とするのが本来の意図に沿った条件分岐になります。 で、 「バージョン 7.0 互換ではない(2010よりもっと古いExcelを使う)かどうか」を判定する必要性も 昨今かなり薄くなってきていると思われますので、アレだったら(そんな心配が無用なら)条件分岐自体不要です。
コンパイラ定数 (VBA) | Microsoft Learn
https://learn.microsoft.com/ja-jp/office/vba/language/concepts/getting-started/compiler-constants
ついでに。 Win64コンパイラ定数が必要になってくる場合の具体例を幾つか。
'▼引数の指定方法を切り替える必要がある #If Win64 Then Declare PtrSafe Function WindowFromPoint Lib "user32" Alias "WindowFromPoint" (ByVal Point As LongLong) As LongPtr #Else Declare PtrSafe Function WindowFromPoint Lib "user32" Alias "WindowFromPoint" (ByVal xPoint As Long, ByVal yPoint As Long) As LongPtr #End If
'▼そもそも関数名(エイリアス)を切り替える必要がある #If Win64 Then Declare PtrSafe Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr #Else Declare PtrSafe Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As Long #End If
'▼使い方によって戻り値がDWORDだったりHWNDだったりする関数で取得したLongPtr値を、別の関数に渡す場合は64bitでは型変換を要したり... #If Win64 Then Private Type typeINT64 Value As LongLong End Type Private Type typeINT32x2 Value1 As Long Value2 As Long End Type #End If Declare PtrSafe Function AdjustWindowRect Lib "user32" Alias "AdjustWindowRect" (lpRect As RECT, ByVal dwStyle As Long, ByVal bMenu As Long) As Long
' 〜本文中〜 Dim h As LongPtr, s As LongPtr, r As RECT s = GetWindowLongPtr(h, GWL_STYLE) '←64bitの場合sはLongLongで下位32bitに値が格納されるので、AdjustWindowRectには下位32bitだけ切り取って渡す Call GetClientRect(h, r) #If Win64 Then Dim t32x2 As typeINT32x2, t64 As typeINT64 t64.Value = s LSet t32x2 = t64 Call AdjustWindowRect(r, t32x2.Value1, False) #Else Call AdjustWindowRect(r, s, False) #End If
とまあ、実際のところそれほど頻繁にはお世話にならないです。 はい。お邪魔しました。
(白茶) 2024/02/09(金) 20:34:21
内容ははっきりと把握できていないのですが、
どのようなことをしたいのかという全体の流れや、
なぜbatファイルやExcelやcsvファイルを使用するかなどのご説明があれば
別方向からの解決策の回答が
皆様からいただきやすいのではないかという気がしました。
ぱっと見でbatファイルを作って作ったbatファイルを起動して削除といった
動作があるような気がするのですが(間違っていたらすみません)
そのようにする理由が想像できませんでした。
白茶さまありがとうございます。
64bitのクリップボードがわからず検索してこちらのサイト様にたどり着いていたので
そちらと合わせて質問スレッドを立てました、申し訳ございません。
https://www.excel.studio-kazu.jp/kw/20240209215611.html
(O.M) 2024/02/09(金) 23:02:31
書いたつもりの前提を私がどこにも書いていませんでした。すみません。
エラーが出るのは、 Set WbTemp = Workbooks.Open(Filename:=CsvFile) です。
CsvFileは、マクロ実行時に毎回新規に作成します(そして毎回消します) CsvFileの中身は、D6(D2&D3連結)で指定したファイルの解析結果です。 元々その作成するにあたって、D2かD3が間違っていると解析結果が出せないため それに伴いCsvFileが作成できず、エラーが出て止まっていました。
問題は、D2とD3の値どちらかが間違っている(存在しないファイルを解析対象に設定している)状態で実行してエラーが出る →D2とD3を正しく直す(存在するファイルを解析対象にする)をしても、CsvFileが作成できない現象が継続する、ということです。 D2とD3が正しく指定されている状態 = CsvFileも正しいパスに正しく生成できる状態 なのに、なぜか動かない という相談でした。 そのままの状態で保存して、再度開いてマクロを実行したらマクロは正常に動きます。という状態で 一度エラーが起きると二度と動かないのでどうしたらいいですか?という意味でした。
現状は、上で申し上げた通りD6に指定しているファイルが存在するかを確認してから 次の処理を実行するようにしているので、問題なくなりました。ありがとうございます。 (元々の正しいファイルをしてもエラーが出続ける原因は解決していないですが、コードも存在しないexeの中の処理が原因っぽいのでどうしようもないなと感じています) (やわら) 2024/02/16(金) 18:28:26
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.