マンガでよめる痔のこと・薬のこと

Excel2010(Windows7 64bit)のVBAであるプログラムを作っていたのですが、以下の様な原因不明のエラーが生じてしまいます。

1. 自分では同じ操作をしているつもりなのですが、エラーが出る場合と出ない場合があり、エラーの原因を特定できません。

2. Errオブジェクトを調べたところ、エラー番号が「-2147417848」です。

3. エラー発生後にExcelがフリーズして数分待っても終了しません。仕方がないのでWindowsを再起動しています。

4. エラーが発生する様になる前は、プログラムは問題なく動いてしました。動かなくなった日に行った変更は、時間がかかるループ内にDoEventsを入れたことと、モーダレスダイアログを表示するようにしたことです。ただ、その他にも細かい変更をしましたし、エラーが発生するタイミングが解らないので、これが原因かはわかりません。

以上です。もし、エラーの原因や解決方法等、何かご存じの方がいらっしゃいましたらご教授くださいますようにお願いいたします。

このQ&Aに関連する最新のQ&A

A 回答 (4件)

おはようございます。



モーダレスフォームが応答なしになるの対策ですが

処理の進歩を示すフォームなら、DoEventsでOSに処理を一旦渡さなくても
UserForm1.RePaintで出来ます。

もし
Label1.Caption = s & "% 処理中・・・"
DoEvnets

みたくなっているのでしたら

Label1.Caption = s & "% 処理中・・・"
UserForm1.RePaint

に置き換えてみるとどうでしょう?

このRePaintも頻繁に呼び出すと画面がちらつきますので呼び出す回数は工夫が必要
です。(例えば、10%毎に呼び出すとか)

VBAは処理速度が遅いので、WinApiのSleepを適度にはさんでやるのもいいのかも
しれません。

複数の環境で使われているみたいですから、条件付コンパイルを使ってSleepを宣言します。

#If VBA7 And Win64 Then
 '64ビット版
  Public PtrSafe Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#Else
 '32ビット版
  Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If

この様に標準モジュールに宣言をして

Do
  Sleep 100
  処理
Loop

とすると応答なしにならなくなります。CPUも100%使い切る事もなくなります。
このSleepは指定時間だけ処理を止めるものですから、コツは短い時間(ミリ秒)
を何度も挟むことです。長い時間はさむと処理もExcelの操作も一切出来ません
ので注意が必要です。

根本的な解決に繋がるか自信がありませんが、何かの参考になりましたら。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。その後、色々試してみました。あるシートのセルにある程度まとまったデータを書き込むループがあったので、その中にDoEventsを入れていたのですが、そのループに入る前にScreenUpdatingをFalseにしていました。これをTrueにしたらエラーが出なくなりました。これが直接の原因だったのかはよく判らないのですが、とりあえずこれで進めてみます。色々お教えいただきましてありがとうございました。

お礼日時:2013/02/25 18:00

No2です。




このようなパターンでないですか?
DoEventsを入れてある無限ループ中にSheet1を手動で削除してみて下さい。
wsはNothingではありませんが、wsの実体がなくなってしまうと
オートメーションエラーになります。

新規ワークbookで試して下さい。

Sub Sample()
  Dim ws As WorkSheet
  Set ws = WorkSheets(1) '一番左のワークシートをセット

  Do
    DoEvents

    If Not ws Is Nothing Then 'wsがNothingでないなら
      Debug.Print ws.Name 'シートを削除すると、ここでオートメーションエラー
    End If
  Loop

End Sub

例はワークシートですが、UserFormへの参照や他諸々のオブジェクト変数の実体が
なくなる様な操作またはコーディングをしていませんか?

DoEventsは諸刃の剣と書きましたが、DoEventsをループ毎に読み込むのは逆に
処理速度を下げてしまいます。

Sub Sample2()
  Dim i As Long
  Dim s As Single

  s = Timer
  For i = 0 To 300000
    DoEvents
  Next
  MsgBox Timer - s
End Sub

Sub Sample3()
  Dim i As Long
  Dim s As Single

  s = Timer
  For i = 0 To 300000
    If (i mod 10000) = 0 Then 'iが10000で割り切れる時だけDoEventsを実行
      DoEvents
  End If
  Next
  MsgBox Timer - s
End Sub

ループ中にキャンセルを受け入れるのにはDoEventsは必要ですが、使用する回数は
極力少なくするのがいいと思います。(少なくするとキャンセルを受け入れるまで少しもた
つきますが。そこは加減で調整です。)
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。その後、いろいろ試してある程度原因となる箇所が解ってきました。あるシートに比較的大きな範囲(A~SS×1~86)のセルに値を入力するループがあり、その中にDoEventsを入れていたのですが、そのループをある条件で呼び出すとエラーが起きるようです。但し、複数のパソコンで実行したところ、発生するパソコンと発生しないパソコンがありました(excelのバージョンは同じ)。また、同じパソコンでも、サブルーチンを呼び出す順番を変えるとエラーが発生しなくなりました。更に、問題となるループ内のDoEventsを消せばエラーは発生しない様です。結局、DoEventsが原因だと考えて良いのだと思うのですが、DoEventsが直接の原因なのか、そもそも存在していたエラーがDoEventsによって顕在化したのかよくわかりませんでした。また、ループ内ではセルに出力する値を計算するコードもありますので、大量のセルに出力すること自体が問題かどうかもよくわかりませんでした。

DoEventsを入れる理由ですが、キャンセルを受け付けるだけならそれほど頻繁にDoEventsを呼ばなくても良いのですが、モーダレスダイアログに「...(応答無し)」と表示されてしまうと第3者がフリーズしたと勘違いしてしまうと思っています。ですので、DoEventsを入れなくても「...(応答無し)」と表示されないようにする方法があれば、ループ内のDoEventsをそれに置き換えれば良いと思うのですが...。

お礼日時:2013/02/24 06:17

こんばんは。



DoEventsは諸刃の剣ですからね。
一概にDoEventsが犯人だと決め付けられませんが怪しいですね。

ループ中にDoEventsを入れ込むと、ループ処理中に割り込みが可能になりますから
何か別の操作をしてしまったりすると、誤動作の原因にはなりますね。
DoEventsを入れた理由は何故でしょう?モーダレスフォームとは、もしかして
処理中を示す自作のプログレスバー的なものですか?

コードの提示がないのでこれ以上はわかりませんが
問題の原因を切り分けて調べて見ましょう。

DoEventsを削除するとエラーはおきなくなるか?
モーダレスフォームの表示をやめると?
この両方をやめると?

など個別に調べてみましょう。

ループ中に別の操作をしているなら"DoEvents"が8割怪しいですよ。
    • good
    • 0
この回答へのお礼

ご回答いただきましてありがとうございます。DoEventsを入れた理由ですが、仰るように、比較的時間がかかるループがいくつかあるので、キャンセルボタンを配置したプログレスバーのようなものを表示して、ループの前後でキャンセルが押されたから調べ、押された場合はプログラムの実行を中止するようにしました。また、そのままだとループ内でダイアログボックスのタイトルに「...(応答なし)」と表示されてしまうので、ループ内にDoEventsを入れました。
エラーの発生原因がわからず、エラーの発生率もそれほど高くないのでなかなか原因を特定できないでいます。DoEventsをコメントアウトしたりして試しているのですが、何となく、DoEventsを頻繁に呼ぶとエラーが発生しているように感じるのですが...。

お礼日時:2013/02/22 05:09

http://schneisen.cocolog-nifty.com/blog/2012/03/ …
上記のサイトに紹介されているケースとは違いますか?

エラーの発生箇所が分からないのであれば、絞り込むよう手を打つしか無いと思います。
具体的には「ある処理を行ったら現象が発生する」というのを徐々に絞り込んでいくということです。

残念ながらご質問の文面からではエラー原因を回答することは難しいと思います。
どうしても回答が必要な場合は、ソースコードの開示をお願いします。
    • good
    • 0
この回答へのお礼

ご回答いただきましてありがとうございました。ご紹介いただきましたサイトに示されているエラー番号が私の場合と同じですので、コレが原因かもされません。調べてみます。ソースコードですが、かなりの量を書いているコードのどこが原因なのか特定できていないため、このサイトに載せることができませんでした。もう少し調べてみます。

お礼日時:2013/02/22 05:17

このQ&Aに関連する人気のQ&A

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

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

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QDoEvents関数って何?

こんにちは。

VBAやプログラミングに詳しい皆様に
教えていただきたい質問があります。

cells(1,1)からcells(5000,1)までの値を消去するときに
処理の進行状況を表示するためにuserform上にプログレスバーを表示したいと思います。

そこで下記のようなコードを入力しました。

userform1.show
for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
next i
unload userform1

しかしこれだとuserformの背景が真っ白になってしまい
ラベルの文字も消えてしまいます。
そこで「EXCEL VBA パーフェクトマスター」という本を見たら

for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
DoEvents
next i
unload userform1
と入力すれば解決することがわかりました。

しかし「DoEvents」についてあまり詳しく書いていなかったのでDoEvents関数をヘルプで見ると、
「発生したイベントがオペレーティング システムによって処理されるように、プログラムで占有していた制御をオペレーティング システムに渡すフロー制御関数です。」

と書いてあるのですが正直、書いてあることがよくわかりません。

どなたかDoEvents関数について、
もう少しわかりやすく教えていただけませんか。
それから、最初に書いたコードで実行すると
ユーザーフォームの背景が真っ白になってしまう原因も
教えていただけませんか?

よろしくお願いいたします。

こんにちは。

VBAやプログラミングに詳しい皆様に
教えていただきたい質問があります。

cells(1,1)からcells(5000,1)までの値を消去するときに
処理の進行状況を表示するためにuserform上にプログレスバーを表示したいと思います。

そこで下記のようなコードを入力しました。

userform1.show
for i =1 to 5000
cells(i,1)=""
userform1.progressbar1.value=i/5000*100
next i
unload userform1

しかしこれだとuserformの背景が真っ白になってしまい
ラベルの文字も消えてしまいます。
そ...続きを読む

Aベストアンサー

簡単に言うと、
OS に制御を渡すってことです。(ヘルプそのまんま)
時間が掛かるループ処理などの場合、ループが終わるまで制御は独占されてしまいます。
ですのでループ中は OS や Excel そのものにも再描画をさせる暇さえ与えません。
途中に DoEvents を入れると制御が OS に渡るので、OS は溜まっていた処理をそこで行うことができます。
結果、フォームの再描画などが行われることになります。

注意点ですが、
Private Sub CommandButton1_Click()
  Dim i As Long

  For i = 1 To 50000
    DoEvents
    Cells(i,1) = ""
  Next i
End Sub

Private Sub CommandButton2_Click()
  MsgBox "hoge"
End Sub

っていうフォームのコードがあった場合、
DoEvents を入れることによって、ループ中にユーザーがCommandButton2 を押すことによって CommandButton2 のクリック イベントも動いちゃいます。
CommandButton1 のクリック イベントではループの前に
CommandButton1.Enabled = False
CommandButton2.Enabled = False
を書いてフォーム上の CommandButton を無効にしておき、ループが終わったら
CommandButton1.Enabled = True
CommandButton2.Enabled = True
と書いて CommandButton を有効に戻してください。

これを工夫すれば、CommandButton2 で CommandButton1 のループを途中キャンセルする処理もすることができます。

Private Canceled As Boolean

Private Sub CommandButton1_Click()

  CommandButton2.Enabled = False

  Dim i As Long
  For i = 1 To 50000
    DoEvents

    If Canceled = True Then
      MsgBox "キャンセルしました"
      Exit Sub
    End If

    Cells(i, 1).Value = ""
  Next i
End Sub

Private CommandButton2_Click()
  Canceled = True
End Sub



コードの行頭にあるスペースは見易さのために全角スペースで作成していますので、これをこのままコピペするとエラーになるかもしれません。
コピペするなら行頭の全角スペースを半角スペースに直してください。

簡単に言うと、
OS に制御を渡すってことです。(ヘルプそのまんま)
時間が掛かるループ処理などの場合、ループが終わるまで制御は独占されてしまいます。
ですのでループ中は OS や Excel そのものにも再描画をさせる暇さえ与えません。
途中に DoEvents を入れると制御が OS に渡るので、OS は溜まっていた処理をそこで行うことができます。
結果、フォームの再描画などが行われることになります。

注意点ですが、
Private Sub CommandButton1_Click()
  Dim i As Long

  For i = 1 To 50000
...続きを読む

QエクセルVBAが途中で止まります

以前別のカテゴリで質問したのですが、そちらでは解決出来なかったので、こちらで改めて質問します。
下記のマクロで、一つのブックからSheet1だけをコピーして来て、少し処理をし、元のブックを閉じるというもので、ブックの数は多くて3000程、少ない時は300位です。
で、このマクロだと900位までですと最後まで行くのですが、それを超えるとリストが95位で止まってしまいます。
自宅で別データを作ってやってみるとうまくいきました。
コピー元のブックにはテキストデータのみで、200文字から500文字程度の大きさしかありません。
ファイル名も50文字程度の物を全部20文字程度まで短くしてもみましたが、ダメでした。
どうかお知恵をお貸しください。

Sub ★1★ブックの結合()
Dim sFile As String
Dim sWB As Workbook, dWB As Workbook, aWB As Workbook
Dim dSheetCount As Long
Dim i As Long
Dim SOURCE_DIR As String

'エクセルデータに変換されたファイルのあるフォルダを選択します。
MsgBox "エクセルに変換されたデータのフォルダを選択"
With Application.FileDialog(msoFileDialogFolderPicker)
If .Show = True Then
SOURCE_DIR = .SelectedItems(1) & "\"
End If
End With

Application.ScreenUpdating = False

'指定したフォルダ内にあるブックのファイル名を取得
sFile = Dir(SOURCE_DIR & "*.xls")

'フォルダ内にブックが無ければ終了
If sFile = "" Then Exit Sub

'集約用ブックを作成
Set dWB = Workbooks.Add

'転記マクロの中のDMリストシートをコピーする
Workbooks("転記用マクロ.xlsm").Worksheets("DMリスト").Copy Before:=dWB.Worksheets("Sheet1")
Application.DisplayAlerts = False
Worksheets(Array("Sheet1", "sheet2", "sheet3")).Select
ActiveWindow.SelectedSheets.Delete
Application.DisplayAlerts = True

'集約用ブック作成時のシート数を取得
dSheetCount = dWB.Worksheets.Count

Do
'コピー元のブックを開く
Set sWB = Workbooks.Open(Filename:=SOURCE_DIR & sFile)

'コピー元のsheet1を集約用ブックにコピー
sWB.Worksheets("sheet1").Copy After:=dWB.Worksheets(dWB.Sheets.Count)

シート転記

'コピー元ファイルを閉じる
Application.DisplayAlerts = False
sWB.Close
Application.DisplayAlerts = True

'セルA2の名前を変更する


'シート名をセルA2の値に変更
'ActiveSheet.Name = Range("A2").Value


'次のブックのファイル名を取得
sFile = Dir()
Loop While sFile <> ""

'集約用ブックを保存する
'dWB.SaveAs Filename:=DEST_FILE


Application.ScreenUpdating = False


End Sub

以前別のカテゴリで質問したのですが、そちらでは解決出来なかったので、こちらで改めて質問します。
下記のマクロで、一つのブックからSheet1だけをコピーして来て、少し処理をし、元のブックを閉じるというもので、ブックの数は多くて3000程、少ない時は300位です。
で、このマクロだと900位までですと最後まで行くのですが、それを超えるとリストが95位で止まってしまいます。
自宅で別データを作ってやってみるとうまくいきました。
コピー元のブックにはテキストデータのみで、200文字から500文字...続きを読む

Aベストアンサー

http://oshiete.goo.ne.jp/qa/8750372.html


例えば、30ファイルあっても10ファイルしか読み込まれない事があり、
エラーメッセージもない、何事もなく終了するが10ファイルしか処理されていない、
常に発生する訳ではなく、マシンが変われば同じデータでもOKだったり、
データが少し変わればOKだったりする。
なので、昨日までOKだったのに、今日データが変わった為、急にダメになったりする。
もし、10ファイル目で発生した場合、何度実行しても必ず、10ファイル目までしか処理されない。
そのファイルがおかしいかと思い、その前後の2~3ファイルを削除しても、
やっぱり、10ファイル目(さっきとは違うファイル)までしか処理されない、
という恐ろしいバグがExcel VBAにありますが、それじゃないですかね?

While文などのループの中に、ワークブックのオープンがあると、
何度目かでオープンが実行されず、エラーなしでスルンと終わります。

回避方法は、Open 文の前に DoEvets の1行を書く事。
だいたいこれで直りますが、これで直らなかったマクロもあったので、
Open 文の後ろにも DoEvets の1行を書いて、前後を DoEvets ではさむと直りました。
安全(?)の為、前後をはさんでおいた方が良いと思います。

こんな感じ:
DoEvents
Workbooks.Open aaa
DoEvents

かなり前(1年くらい?)にハマりググりまくったところ、ほとんど情報はなかったですが、
1人だけ、自分の質問に「直った」と自己回答している方がいて、Open文の前にDoEvetsをつけたら直ったそうです。
半信半疑で真似たら私も直りました。
何故、これで直るのかはわかりませんが、DoEvetsを外すと見事に再現し、DoEvetsではさむとピタッと直ります。

ググりまくった際、とても情報が少なく、こんなに顕著に再現するのに、
何故、情報が少ないのかは不思議に思いました。

http://oshiete.goo.ne.jp/qa/8750372.html


例えば、30ファイルあっても10ファイルしか読み込まれない事があり、
エラーメッセージもない、何事もなく終了するが10ファイルしか処理されていない、
常に発生する訳ではなく、マシンが変われば同じデータでもOKだったり、
データが少し変わればOKだったりする。
なので、昨日までOKだったのに、今日データが変わった為、急にダメになったりする。
もし、10ファイル目で発生した場合、何度実行しても必ず、10ファイル目までしか処理されない。
そのファイルがおかし...続きを読む

QExcel VBA で処理中断(DoEvents)ができなくて困ってい

Excel VBA で処理中断(DoEvents)ができなくて困っています。

まず、CommandButton1ボタンでSampleをコールし、Sample処理の中でループを廻し、途中でCommand1ボタンをクリックして、処理中断(DoEventsによって)をいれたいと思っています。

しかし、Command1ボタンをクリックしても処理中断がきかないのです。
グローバル変数fStopにはCommand1ボタンをクリックしたときにTrueが入っていることは、MsgBoxで確認していますが、Sample処理の方に値がつたわっていないようで、ループが最後まで止まりません。
コードが悪いのでしょうか、それとも、DoEventsの使い方が悪いのでしょうか。
もし、DoEventsが使えないのであれば、代替手段はありますでしょうか。
(長時間の印刷中の処理中断に応用したいと思っています)

環境はExcel 2002 SP3 , VB 6.0 , Windows XPです。
なお、DoEventsのコードは以下のURLを参考にして作成しました。
http://officetanaka.net/excel/vba/function/DoEvents.htm

コードは以下のとおりです。
'*********
Dim fStop As Boolean 'グローバル変数を宣言
'*********
Sub Sample()
Dim i As Long
fStop = False
For i = 1 To 1000000
DoEvents
If fStop = True Then
MsgBox "処理が中断されました"
Exit For
End If
Next i
End Sub
'********
Private Sub CommandButton1_Click()
Call Sample
End Sub
'********
Private Sub Command1_Click()
fStop = True
MsgBox "fStop=" & fStop
End Sub

Excel VBA で処理中断(DoEvents)ができなくて困っています。

まず、CommandButton1ボタンでSampleをコールし、Sample処理の中でループを廻し、途中でCommand1ボタンをクリックして、処理中断(DoEventsによって)をいれたいと思っています。

しかし、Command1ボタンをクリックしても処理中断がきかないのです。
グローバル変数fStopにはCommand1ボタンをクリックしたときにTrueが入っていることは、MsgBoxで確認していますが、Sample処理の方に値がつたわっていないようで、ループが最後まで止まりません。
コ...続きを読む

Aベストアンサー

当方xl2000ですが、提示されたコードで問題なく動作いたしました。
動作が分かり易いようにラベルを一個追加しています。
Dim fStop As Boolean

Sub Sample()
Dim i As Long
fStop = False
For i = 1 To 1000000
DoEvents
Me.Label1.Caption = i
If fStop = True Then
MsgBox "処理が中断されました"
Exit For
End If
Next i
End Sub

Private Sub CommandButton1_Click()
Call Sample
End Sub

Private Sub CommandButton2_Click()
fStop = True
MsgBox "fStop=" & fStop
End Sub

Private Sub UserForm_Initialize()
Me.Label1.Caption = 1
End Sub

'○標準モジュール
'Sub test()
' UserForm1.Show 'vbModeless
'End Sub

当方xl2000ですが、提示されたコードで問題なく動作いたしました。
動作が分かり易いようにラベルを一個追加しています。
Dim fStop As Boolean

Sub Sample()
Dim i As Long
fStop = False
For i = 1 To 1000000
DoEvents
Me.Label1.Caption = i
If fStop = True Then
MsgBox "処理が中断されました"
Exit For
End If
Next i
End Sub

Private Sub CommandButton1_Click()
Call Sample
End Sub

Private Sub CommandButton2_Click()
fStop = True
MsgBox "fStop=" & fStop
End Sub

Private Sub UserForm_Initial...続きを読む

QエクセルVBAのIf,Then 構文でOr条件とAnd条件の結合方法?

ワークシート関数で書けば
=IF(OR(F18=0,AND(F15>0,F16>0)),TRUE)です。
これをVBAで書こうとして

If Sheet1.Range("F18") = 0 Or Sheet1.Range("F15") > 0 And Sheet1.Range("F16") > 0 Then
MsgBox True
Else
MsgBox False
End If

とやってみたのですが、正しくないようです。
どのように書けばいいのでしょうか?

Aベストアンサー

>とやってみたのですが、正しくないようです。

式は正しいと思いますよ

ANDとORは、ANDが先に演算されます。/*と+-では、/*が先に演算されるようなものです。

でも、わかり易くするために、#1のかたのように括弧をつけるほうが良いですね。

QEXCELファイルのカレントフォルダを取得するには?

EXCELファイルのカレントフォルダを取得するには?

C:\経理\予算.xls

D:\2005年度\予算.xls

EXCEL97ファイルがあります。

VBAで
  カレントフォルダ名
(C:\経理\,D:\2005年度\)
を取得する事は可能でしょうか?

CURDIRでは上手い方法が見つかりませんでした。

Aベストアンサー

こんばんは。
Excel97 でも、同じですね。以下で試してみてください。

Sub test()
'このブックのパス
a = ThisWorkbook.Path
'アクティブブックのパス
b = ActiveWorkbook.Path
'Excelで設定されたデフォルトパス
c = Application.DefaultFilePath
'カレントディレクトリ
d = CurDir
MsgBox "このブックのパス   : " & a & Chr(13) & _
   "アクティブブックのパス: " & b & Chr(13) & _
   "デフォルトパス    : " & c & Chr(13) & _
   "カレントディレクトリ : " & d & Chr(13)
End Sub

Q別のシートから値を取得するとき

Worksheets("シート名").Activate
上記のを行ってから別シートの値を取得するのですが、
この処理を行うと指定したシートへ強制的にとんでしまいます。。。

※イメージ
For ~ To ~
  Worksheets("シートA").Activate
  シートAの値取得
       :
  Worksheets("シートB").Activate
  シートBの値取得
Next

このイメージ処理を行うとものすごい勢いで画面がチカチカします。。。
シートを変えずに他のシートから値を取得する方法はないのでしょうか。
教えてください!

Aベストアンサー

Worksheets("シートA").Range("A1")

みたいな感じでできませんか?

QVBA エンターキーでイベントに入りたい。

テキストボックスにデータ入力後エンターキーの押下でイベントに入りたいのですが、下記のコーディングで[通過]メッセージが表示されません。英数字は通過しますが、エンターキーは動作停止します。
これと全く同じコーディングでVB6は正しく動きます。(ただし、Pvate Sub text1_KeyPress(KeyAscii As Integer)に変更してます。)
<コーディング>
Private Sub TextBox1_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
Msgbox "通過"
If KeyAscii = vbKeyReturn Then
KeyAscii = 0
End If
End Sub

これが出来ると、そのつどキーボードから手を離さずに済むので作業効率がグンとあがります。どうかよろしくご教示ください。Excel2003SP3

Aベストアンサー

こんにちは。

>ご指摘のオブジェクトとプロシージャは間違いないことを確認しています。(TextBox1,keyPress)コードのロジックはこれ以上簡単に書きようがないほど単純明快です。

>Excelで実際にこのコードを実行していただけませんか。

ご自身のコードが間違いがないと思い込んでいられるから、そういう発言をされるのだと思いますが、ここでのお話の前提は、あくまでも、VBAです。VB6ではありません。

私が、期待通りの反応を示さないので、「実際にこのコードを実行してください」とおっしゃっているようですが、はっきり言えば、その最初のコードは、VBAでは間違っています。それに気がついてください。

質問のコードのままのコードでは、Enter キーのイベントは、取れないのです。別にPCの故障でもソフトの問題でもないし、こちらが試していないわけでもありません。

Visual Basic とVBAは、細かい点で違います。

VBAのこの種のイベントの KeyAscii では、VB6 で取れる、EnterキーのKeyAsciiの 「13」 は、取れません。 KeyAscii は、MSForms.ReturnIntegerとなって、Integer ではありません。

だから、私は、その代わりとして、KeyDown イベントを使えばよいとしているわけなのです。

Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
 If KeyCode = vbKeyReturn Then
  MsgBox "Enterキーが入りました", 64
  'KeyCode =0
 End If
End Sub

Private Sub TextBox1_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
 MsgBox "通過"
End Sub

こんにちは。

>ご指摘のオブジェクトとプロシージャは間違いないことを確認しています。(TextBox1,keyPress)コードのロジックはこれ以上簡単に書きようがないほど単純明快です。

>Excelで実際にこのコードを実行していただけませんか。

ご自身のコードが間違いがないと思い込んでいられるから、そういう発言をされるのだと思いますが、ここでのお話の前提は、あくまでも、VBAです。VB6ではありません。

私が、期待通りの反応を示さないので、「実際にこのコードを実行してください」とおっしゃってい...続きを読む

Q【Excel VBA】 WorksheetやRangeオブジェクトとして宣言した変数の開放は必要でしょうか?

こんばんは。

プロシージャレベルで宣言したWorksheetやRangeなどのオブジェクト変数に対し、
プロシージャを終了する直前に、
Set ○=Nothing
を実行して、変数(オブジェクトへの参照)を開放する処理を習慣的行っていました。

これは、絶対に必要な処理なのでしょうか?
開放しないことで不具合が出るケースとはどういう場合なのでしょうか?

どなたか、ご教示いただけないでしょうか。
よろしくお願いいたします。

<例>
Sub test()
  Dim Ws1 As Worksheet
  
  Set Ws1 = Worksheets("Sheet1")

  '処理内容
  
  Set Ws1 = Nothing
End Sub

尚、CreateObject関数で作成したオブジェクトへの参照などではなく、
あくまでもWorksheetやRangeなどの話です。

Aベストアンサー

プロシージャレベルの Worksheet や Range オブジェクトでは、
プロシージャの終了とともに自動開放されますから、 Nothing に
よる開放処理は必須ではありません。

長く VBA を使っておりますが、省略したからといって不具合が発生
したケースも経験ありません。

ただ、プログラムを書く姿勢として、

  自分で使ったモノは、自分で開放する

とあるべきではないかと考えます。

VBA においてはマナーみたいなものですね。されど、これは私個人
だけの考えではなく、過去から積み上がった先人プログラマーの
経験側でもあります。

例えば、VBA のこのような言語仕様に慣れきった人、つまり開放
するということが習慣として身についていない人が、メモリ操作や
画像処理など高度な処理を書くようになった場合、必須の開放処理
が抜け落ちたプログラムを平気で書いてしまい、後々メモリリーク
に悩むはめになったりしがちです。

言語仕様として、「必須ではない」とはいえ、きちんと開放処理を
記述した方が良いでしょう。

注意が必要なのは、オートメーションを使ったプログラムの場合は、
例えプロシージャレベルであっても開放必須です。これを怠ると
#1 でお話がでてますが、いわゆるゾンビプロセスが残るという事態
になります。また、

> プロシージャレベルで宣言したWorksheetやRangeなどの...

と限定されているのでお分かりかと思いますが、グローバル等の
広域変数の場合も、誤動作防止、余計なメモリ消費を抑えるため
適所で開放処理が必須になります。

余談になりますが、#1 補足欄のソースは私ならこう書きます。
ご参考までに。

Sub test()
  On Error Goto Err_
  Dim Ws1 As Worksheet
  Set Ws1 = Worksheets("Sheet1")

  '処理内容
  
Bye_:
  Set Ws1 = Nothing
  Exit Sub
Err_:
  'エラー処理
  Resume Bye_
End Sub

プロシージャレベルの Worksheet や Range オブジェクトでは、
プロシージャの終了とともに自動開放されますから、 Nothing に
よる開放処理は必須ではありません。

長く VBA を使っておりますが、省略したからといって不具合が発生
したケースも経験ありません。

ただ、プログラムを書く姿勢として、

  自分で使ったモノは、自分で開放する

とあるべきではないかと考えます。

VBA においてはマナーみたいなものですね。されど、これは私個人
だけの考えではなく、過去から積み上がった先人...続きを読む

QDLLが正しく呼び出せません (ToT)

こんにちは。よろしくお願いします。

環境は、WindowsXP Access2000/VBA にてプログラミングをしています。
現在、表題の「DLLが正しく呼び出せません」エラーに泣かされています。。。。
どなたかもし心当たりなどありましたらぜひアドバイスを下さい。

VBAにてシステムを作成していますが、その中で、普通に自分で書いた関数を
普通に?呼び出しているだけなのですが、表題のエラーが頻発してしまい困っています。

別に、外部DLLをDeclareしてそれを呼び出した時に出ている、という事ではないです。
普通に自分で書いた関数を呼び出すだけなんですが、ある関数を呼び出すと、
返ってくる時にこのエラーが発生するものがあります。(SubでもFunctionでも)

引数の型や戻り値の型は、呼び出し側と整合が取れています。(確実に一致しています)

まったく原因がわからないので、例えばエラーの出た関数がSubの場合は
一応 Call をつけて呼び出してみたりするとその場はエラーがなくなったりして
でも、またその関数の中を編集したりすると、いつのまにかまた
その関数を呼び出した時に表題のエラーがでたりします。

もちろんコンパイルエラーはありませんし、SetしてNothingを忘れてメモリを壊している
という事などもないつもりです。
(エラーのでる関数ではそもそもSetなどを使っていませんし)

DLLの関数を呼び出すのではなく普通に標準モジュールなどに書いた自前の関数の呼び出しで
表題のエラーがでる原因として、なにか考えられる事はあるのでしょうか。

実際のソースを載せれないので申し訳ないですが、一般的な情報として
「DLLが正しく呼び出せません」エラーの原因となる事をどのような事でもけっこうですので
教えていただければ、と思います。

どうかよろしくお願いいたします。

こんにちは。よろしくお願いします。

環境は、WindowsXP Access2000/VBA にてプログラミングをしています。
現在、表題の「DLLが正しく呼び出せません」エラーに泣かされています。。。。
どなたかもし心当たりなどありましたらぜひアドバイスを下さい。

VBAにてシステムを作成していますが、その中で、普通に自分で書いた関数を
普通に?呼び出しているだけなのですが、表題のエラーが頻発してしまい困っています。

別に、外部DLLをDeclareしてそれを呼び出した時に出ている、という事ではないです。...続きを読む

Aベストアンサー

VB/VBAから呼び出すDLLの関数は、Microsoft C/C++の用語で言うところのSTDCALL呼び出し規約でなければなりません。

呼び出し規約がSTDCALLでない関数(例えばcdecl呼び出し規約の関数)をVB/VBAから呼び出すと、関数の呼び出し自体は行われますが、関数の実行から戻ってきた時点で「DLLが正しく呼び出せません」エラーになります。

また、STDCALL呼び出し規約の関数であっても、呼び出し時に引数の数やサイズを間違えていると、やはり関数の実行から戻ってきた時点で「DLLが正しく呼び出せません」エラーになります。

このほか、呼び出された関数が何らかの理由(通常はプログラムミス=バグ)によりスタックポインタを通常あるべき値とは異なる値にして実行を終了すると、関数の実行から戻ってきた時点で「DLLが正しく呼び出せません」エラーになります。

QExcel VBAで、ユーザーフォームの値を、モジュールで使用したい。

VBA初心者です。(おそらく)基本的な質問で、申し訳ありません。
ユーザーフォーム1には、テキストボックス1とコマンドボタン1が配置されているとします。

Sub TEST ()
Dim N
Userform1.Show
MsgBox N
End Sub

Private Sub CommandButton1_Click()
Dim N
N = TextBox1.Text
UserForm1.Hide
End Sub

Sub TESTを実行した時に、ユーザーフォーム1からNの値を引き継ぐには、どうしたら良いのでしょうか?よろしくお願いします。

Aベストアンサー

'モジュールに変数宣言(グローバル変数)
'Public 宣言すると他のモジュールやフォームと
'共有できる変数になります。
Public AA As String

'sample
'A1 を実行する。

Sub A1()
Call A2
AA = InputBox("input", , AA)
End Sub

Sub A2()
AA = InputBox("input", , AA)
End Sub


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング