質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.21%

【Excel】【VBA】Chart オブジェクト の MouseDown イベント・BeforeDoubleClick イベント で発生する、メモリ不足エラーの原因 を突き止めたい

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 845

vvvpp

score 4

まえがき

文字数制限にひっかかってしまったため、一部のコードを消去しました。
消去したコードにつきましては、編集履歴 の方からご確認いただけます。

前提・実現したいこと

先日、VBA(Excel)で、アクティブなChart の名前を取得するべく、
Chart オブジェクト の MouseDownイベント を用いたプラグラム を組みました。

しかし、そのイベントが連続的に実行された場合、
以下のエラーメッセージが発生してしまいます。

このエラーを回避するコードは組めたのですが、
結局、エラーが発生する原因は分かりませんでした。

今後、同様のエラーを発生させないためにも、
このエラーの原因を突き止めたいです。

エラーメッセージ(Microsoft Excel)

この操作を完了するにはメモリが不足しています。
扱うデータ量を減らすか、他のアプリケーションを終了してください。
使用できるメモリを増やすには、以下を検討してください。
- 64ビット版の Microsoft Excel を使う。
- デバイスのメモリを増設する。

エラーメッセージ(イベント ビューアー)

障害が発生しているアプリケーション名: EXCEL.EXE、バージョン: 16.0.4966.1000
障害が発生しているモジュール名: oart.dll、バージョン: 16.0.4900.1000
例外コード: 0xc0000005

該当のソースコード

ここには エラー発生の原因となるコードを載せます。
全体のコードは【ソースコード(全体)】に載せてあります。

' TestChart
Public WithEvents TargetChart As Chart

Private Sub TargetChart_MouseDown(ByVal Button As Long, ByVal Shift As Long _
                                , ByVal x As Long, ByVal y As Long)

    Debug.Print sheet_.ChartObjects(ActiveChart.Parent.Index).Name ' エラー発生

End Sub

【ソースコード(全体)】

Public sheet_ As Worksheet
Private class_ As New TestChart

Sub Set_Data()

    Set sheet_ = ThisWorkbook.Sheets("Main")
    Set class_.TargetChart = sheet_.ChartObjects("Chart 1").Chart

End Sub
' TestChart
Public WithEvents TargetChart As Chart

Private Sub TargetChart_MouseDown(ByVal Button As Long, ByVal Shift As Long _
                                , ByVal x As Long, ByVal y As Long)

    Debug.Print sheet_.ChartObjects(ActiveChart.Parent.Index).Name ' エラー発生

End Sub
Private Sub Workbook_Open()
    Call Set_Data
End Sub

エラー発生の経緯

(シート上には、空のChart(種類:2-D 集合縦棒, 名前:グラフ 1)が一つ 存在しています)

上記ソースコードのイベントが実行された場合、
私は 次のように出力されると予測しました。

Chart 1 ' 予測した結果

実際には、次のように出力されました。

Chart 1 ' 実際の結果

予想した通りの結果となったため、デバッグ作業に移りました。

デバッグとして、Chart を連続的にクリックし、MouseDown イベントを発生させ続けたところ、
上記のエラーが発生してしまったのです。

タスク マネージャー

タスク マネージャー の 【アクティブなプロセスで使用されている物理メモリ】

  • エラー発生前:68 %
  • エラー発生後:69 %

32bitアプリのメモリ上限は2GB…であってますよね?
vbaが2GBフルで使用できるわけではないかと思いますが(Excel本体の機能の分があるため)、
それにしても Excelに割り当てられているメモリが少なすぎるように感じます。

【このプロセスで使用されているため別のプロセスでは使用できない物理メモリの量(中断された UWP プロセスを除く)】の推移

(EXCEL.EXE)

・【' エラー発生 の コード】:増える。

クリック回数 物理メモリの量
0 38,112 K
1 39,264 K
2 39,640 K
3 39,860 K
4 40,932 K
5(エラー発生) 41,088 K

・【' 問題なし の コード】:増えない。
・イベントを無効にした状態(コメントアウト)で検証:増えない。

解決方法

上記コードを次のように変更したところ、
エラーは発生しなくなりました。

Debug.Print sheet_.ChartObjects(ActiveChart.Parent.Index).Name ' エラー発生
Debug.Print ActiveChart.Parent.Name ' 問題なし

しかし、エラー発生の原因は分からないままだったため、
原因の追究をすることにしました。

試したこと(1)

【sheet_.ChartObjects(ActiveChart.Parent.Index).Name ' エラー発生】

【ActiveChart.Parent.Name ' 問題なし】
という結果から、【.(ピリオド)】の個数に注目しました。

VBAメモリーリークについて

こちらを参考にして、次のコードを組んでみました。

編集履歴をご参照ください。

結果は変わらず、同じエラーが発生しました。

次に、【sheet_.ChartObjects(ActiveChart.Parent.Index).Name】
に原因があるのかを調べるため、次のコードを実行してみました。

編集履歴をご参照ください。

結果は問題なし。

【sheet_.ChartObjects(ActiveChart.Parent.Index).Name】
でもエラーが発生しないということは、【MouseDown イベント】に問題がある と考え、
そちらに注目し、原因の追究をすることにしました。
(【試したこと(2)】に続きます)

試したこと(2)

まずは、【MouseDown イベント】以外のイベントだとどうなるのか、
検証してみました。

ただし、【空のActiveChart】という前提 に合わないイベントは、
検証するイベントから除いています。

結果は次の通りです。

イベント Debug.Print sheet_.ChartObjects(ActiveChart.Parent.Index).Name Debug.Print ActiveChart.Parent.Name
MouseDown  エラー発生 問題なし
BeforeDoubleClick  エラー発生 問題なし
Activate  問題なし 問題なし
MouseMove  問題なし 問題なし
Resize  問題なし 問題なし

検証の結果、【MouseDown イベント】だけではなく、
【BeforeDoubleClick イベント】でも同じエラーが発生する ことを確認できました。

そこで、次は【BeforeDoubleClick イベント】から、次のコードを検証してみました。

編集履歴をご参照ください。


結果は、【MouseDown イベント】と同様のエラーが発生しました。
(【試したこと(3)】に続きます)

試したこと(3)

Chart クリック → 適当なセルをクリック

というのを繰り返した結果、エラーが発生しませんでした。

これに注目し、イベント間に何かしらの処理を挟んでみる ことにしました。
次は、検証用のコードとなります。

編集履歴をご参照ください。

上記コードを実行し、Chart クリック → sheet_.Range("F2").Select

というのを繰り返した結果、エラーが発生しませんでした。

検証を深めるため、上記コードを次のように変更してみました。

編集履歴をご参照ください。

上記コードを実行し、Chart クリック → sheet_.Range("F2") = boolean_

というのを繰り返した結果、エラーが発生しました。
(【試したこと(4)】に続きます)

試したこと(4)

次に、Chart 1 クリック → Chart 2 クリック

というのを繰り返した結果、エラーが発生しませんでした。

編集履歴をご参照ください。

これに注目し、次のコードを検証してみました。

編集履歴をご参照ください。

上記コードを実行し、
Chart 1 クリック → sheet_.ChartObjects("Chart 2").Chart.ChartArea.Select

というのを繰り返した結果、エラーが発生しませんでした。
(Chart 一つに使用できるメモリの量が決められていて、そのメモリが、
【セル や 他のChart の Select】が行われるまで解放されない…ということでしょうか?)
(【試したこと(5)】に続きます)

試したこと(5)

その他、次のことを試してみましたが、
結果は変わらず、同じエラーが発生するだけでした。

  • 【ハードウェアグラフィックスアクセラレータを無効にする】を選択する
  • 違う種類のChart(円・折れ線)を使用する
  • book の修復
  • アドイン の無効化
  • Debug.Print sheet_.ChartObjects(ActiveChart.Parent.Index).Name
    を、Sub プロシージャ に移し、イベントから、そのプロシージャを呼び出すようにする
  • ステップイン実行【イベント処理終了時(End Sub 到達後、[F8 キー]押下)、エラー発生】
    (これにより、処理の終了前に次の処理が開始される → 処理が追いつかなくなってエラー
    …という可能性もない、と考えてよさそうです。正直、一番ありえそうな原因だったのですが…

同様の症状について探していたところ、次の質問が見つかりました。
Excel vba でメモリが不足しています。っと表示されて処理が完了できない。

エラーメッセージ はドンピシャだったのですが…
私は、【カメラ 機能】も【リンクされた図】も【数式】も【名前の定義】も
使用(追加)していません。
(そもそも、Excelファイル新規作成 → 空のChartを挿入 → 上記ソースコード を記入
…しか行っていないファイルのため、肥大化とかはしていない…はずです。
念のため、上の手順で同じファイルを作成してみましたが、何も変わりませんでした)

また、次の環境で試してみたところ、エラーは発生しませんでした

Windows 7 Home Premium
メモリ:8.00 GB
Excel 2010 64bit(14.0.7237.5000)

追記:試したこと(6)

sazi 様 からのご指摘を受け、次のコードの検証を行いました。

Public sheet_ As Worksheet
Public flag_ As Boolean
Private class_ As New TestChart
Private class2_ As New TestChart _

Sub Set_Data()

    Set sheet_ = ThisWorkbook.Sheets("Main")
    Set class_.TargetChart = sheet_.ChartObjects("グラフ 3").Chart
    Set class2_.TargetChart = sheet_.ChartObjects("グラフ 1").Chart
    flag_ = False

End Sub
Private Sub TargetChart_BeforeDoubleClick(ByVal ElementID As Long, ByVal Arg1 As Long,
ByVal Arg2 As Long, Cancel As Boolean)   

    DoEvents

    If flag_ = False Then

        flag_ = True

        Debug.Print sheet_.ChartObjects(ActiveChart.Parent.Index).Name ' エラー発生

        flag_ = False

        DoEvents

    End If

End Sub


検証の結果、エラーが発生しました。

ステップイン実行 でもエラーが発生していることもあり、
イベント処理中に他のイベントが邪魔をしている、のではなく、
イベント終了時の処理 のどこかに【エラー発生の原因】
ひそんでいるのではないか、と疑っております。
(【試したこと(5)】のステップイン実行でも、
End Sub 到達後の[F8 キー]押下により、エラーが発生しています)
(【追記:試したこと(7)】に続きます)

追記:試したこと(7)

クリックに間をおくとどうなるか、検証してみました。

・【 1 分 間隔 で Chart を クリック 】

クリック回数 物理メモリの量
0 37,316 K
1 35,972 K
2 35,524 K
3 35,516 K
4(エラー発生) 34,348 K

・【 2 分 間隔 で Chart を クリック 】

クリック回数 物理メモリの量
0 32,672 K
1 35,240 K
2 34,320 K
3 34,292 K
4 34,364 K
5 35,308 K
6(エラー発生) 33,344 K

クリック間に時間をおいても、エラーは発生しました。
また、メモリの方もよくわからない結果になってしまいました。
メモリ不足のエラーの割に、メモリはあまり関係なかったりするのでしょうか?

最後に

まとめると次のようになります。

同じ Chart を 連続的にクリックして、
【MouseDown イベント】や【BeforeDoubleClick イベント】で
特定のコードを実行し続けた場合、エラーが発生する。

【同じ Chart 】というのが、エラーが発生する原因のポイントではないか、と疑っているのですが…

情けない話ですが、私ではこれ以上どう検証していけばいいのか、皆目見当もつきません。

(検証にかけた時間の割に 分かったことが少なすぎて、泣きそうです)

エラー発生の原因について、情報いただけますと幸いです。
よろしくお願いします。

できないこと

わけあって、次の事項を行うことはできません。

・インストール
・管理者権限の必要な設定の閲覧・変更
・レジストリキーの値の変更
・Office アプリケーションの修復
・保護ビューの設定 の 変更(現在、3つの項目すべてに チェックがついている状態 です)

補足情報

Windows 10 Pro
メモリ:4.00 GB
Excel 2016 32bit(16.0.4966.1000)

ファイルサイズ 22 KB

Sheet1(Main)
空のChart(種類:2-D 集合縦棒, 名前:グラフ 1)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

原因究明に役立つか分かりませんが、取りあえずコメントします。
VBAはイベントドリブン(イベント駆動型)で、それらのイベントは時系列を保って制御されるわけではありません。

なので、イベント処理中に他のイベントが動作する事もあり得ます。
そうすると予期しない動作が発生します。

回避方法としては、
・グローバルなイベント実行中のフラグを準備し、イベント開始/終了でフラグのセット/リセット。
イベント処理内では、セット/リセットの前に判定し、実行中であれば処理しないようにする。
・処理実行後や処理前にDoeventsを実行しイベント処理の実行を促す。

等が考えられます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/12 22:54

    マウスボタンを押す、サイズを変更する、といった、
    ユーザーの行為をイベントとしてキャッチし、
    それに対応したプログラムを実行する……といった認識です。

    今回、その対応したプログラムについて記載してあるイベントは
    【MouseDown イベント】のみのため、通常のクリック(ダブルクリックではない)で
    検証した場合、頂いたURLでいうと、

    ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
    マウスボタンを一回クリックしたときのイベントは次のような順序で発生する。
    1-1.MouseDown
    1-2.Click
    1-3.MouseClick
    1-4.MouseUp
    また、マウスボタンをダブルクリックしたときは次のような順序でイベントが発生する。
    2-1.MouseDown
    2-2.Click
    2-3.MouseClick
    2-4.MouseUp
    2-5.MouseDown
    2-6.DoubleClick
    2-7.MouseDoubleClick
    2-8.MouseUp
    ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

    【1-1.MouseDown】でのみ イベントがキャッチされ、プログラムが実行される。

    ……でしょうか。申し訳ありませんが、ちょっと自信ないです……。
    (浅学なため、分かり辛く曖昧な回答となってしまいました。申し訳ございません。
     誤って認識している部分がありましたら、ご指摘いただけますと幸いです)

    キャンセル

  • 2020/05/12 23:12 編集

    厄介なのは、発生したイベントの順番通りに制御が廻ってくるとは限らないところです。
    イベントリスナーの機能が備わっていないものでは、イベント処理は極力組み込まない方が無難です。
    例えば、「実行」ボタンで纏めて処理するようにするとか。
    私自身も過去に懲りたので、イベント処理は極力作らないようにしています。

    キャンセル

  • 2020/05/12 23:29

    なるほど……勉強になりました。
    今度からは、そのようなイベント処理を組み込まなくてすむような設計をしていきます。

    ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.21%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • VBAに関する質問
  • 【Excel】【VBA】Chart オブジェクト の MouseDown イベント・BeforeDoubleClick イベント で発生する、メモリ不足エラーの原因 を突き止めたい