[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『 パブリック変数が何かのタイミングで破棄される可能性がある事象の対策』(隠居じーさん)
こんばんは ^^ いつもお世話になっております。 1. D:¥excel\フォルダ内にマクロブック、pvtest.xlmsを作成 2. 同フォルダに新規ブック(book1)を同名のxlamファイルを作成 3. pvtest.xlmsから参照設定でpvtest.xlamを参照設定 4. pvtest.xlamのプロジェクト名をpに 5. pvtest.xlamのthisworkbookのオブジェクト名をvに変更 6. 5.のvのコード表示で
Option Explicit Public cnt As Long
を記述 7. pvtest.xlamを上書き保存 pvtest.xlmsの標準モジュールに下記コードを記述
Option Explicit Sub test() v.cnt = 1000 MsgBox v.cnt End Sub Sub test2() For v.cnt = 1 To 10 MsgBox v.cnt Next End Sub
testは正常作動 test2 はコンパイルエラー! ”変数が必要です”とエラーメッセージが出ます。
ご教授戴きたい点は 以前この学校でこのような回避策をお取りになり、 完全とは言えないまでも実用に支障は出ていないような趣旨 をおききしたもので。この方法で良いのか。他に対策案があれば 教えていただきたいのと。 現状では、ループカウンターに使うとエラーになります。?? 多分私が設定を間違えているのだと思いますが、 この辺の当たりもお詳しい方がおられれば、お教えいただけると幸甚 です。宜しくお願い致します。
< 使用 Excel:Excel2016、使用 OS:Windows10 >
この時、開いている全てのブックの変数が消失すると思うのですが、そうなると別のブックにデータを退避することで対策にはならないと思うのですが、私の思い違いでしょうか?
この手の対策はワークシートに書き出すとか、外部ファイル・レジストリに書き出すのが普通だと思うのですが。
一応、そのコードを試してみましたが此方でも再現できました。
変数として代入はできるのに、ループカウンタには出来ない。不思議な挙動です。
それならそれで、こうすればいいのでは?と思いますが。
Sub test2() Dim i As Long For i = 1 To 10 p.v.cnt = i MsgBox p.v.cnt Next End Sub そもそも、このような使い方をする状況が私には想像できません。 (名無し) 2018/10/22(月) 09:30
名無し さん ご回答ありがとうございます。
>>パブリック変数が消える時ってENDステートメントを 実行した時とかエラーで強制終了した時とかのことですよね? ============================================= 私もその辺が良く分かりません。 マイクロソフトさんのご説明だと。。。 メモリーの自動解放システムがエクセル様は独特で。。 たまに普通〜に使っていても突然消えて無くなる 事も有るかもしれないので使う時は気を付けましょう ^^ いやなら セルに書き出しましょうね。 って事かな、と想像しているのですが。 ============================================= >>そもそも、このような使い方をする状況が私には想像できません。 すみません。 何時消えるか分からない恐怖から解放されのびのびと、各処理を部品化したコードを 書きたくて、考えています。
別BOOKを使用するのは参照しているだけなので(開いているよ〜なきがしないでもありません) メモリーお掃除システム様の処理対象外なのかな〜とか想像するのですが。。。 それだとメモリリークなど心配は無いのか。。。疑問は深まるばかりで 諸先輩の皆様のご経験、お知恵等ご拝借できればと思います。
上記コードをpvtest.xlamの標準モージュールに記述すればループカウンターでも使えます。 thisworkbookモジュールってクラスモジュールでしょうか? でもクラス、作ればうまく動かないです。 頭の中かがグチャグチャになりかかっている老人(もちろん私の事)でした。 m(__)m
(隠居じーさん) 2018/10/22(月) 10:44
そして、確認のためとは思いますが、ループ変数に共通変数をつかうべきではないでしょう。 変数はなるべく小さいスコープで定義し使用するのが、余計な不具合を出さないためのセオリーですから。
更には、クラスと共通変数って、相反するものです。 共通変数のように引数宣言を無視して横槍を入れるようなものを排除し、Input,Outputを明確に宣言し、内部処理は独立していて外からは見えない、というのがクラスというものかと思います。
(???) 2018/10/22(月) 11:12
(隠居じーさん) 2018/10/22(月) 15:03
「たまに消える」なんて、もし使っていて不正動作があってもMSは保証しませ〜ん!、と言っているようなものです。 そんな曖昧な機能なんて、使っちゃ駄目ですね。(この手の不具合をMSが認めても、修正したパッチを出した事が無いように思います)
(???) 2018/10/22(月) 15:33
(隠居じーさん) 2018/10/22(月) 16:47
MSの前の文言はこうでした。メモってくれてた人がいました。
>ある Office ドキュメントが VBA のマクロを含む場合、 >その中のモジュールに記述された Public 変数の値が有効である期間は、 >あるプロシージャの実行を開始し、そのプロシージャが “End Sub” で終了するまでの間のみです。 > >ほとんどの場合、プロシージャ終了後も値は保持されますが、 >意図しないタイミングで保持されていた Public 変数の値が破棄され、 >使えていた変数の値が突然使えなくなる場合があります。 > >そのため、Public 変数がアプリケーション終了時まで有効であることを期待する >VBA マクロの実装は、推奨されません。 > >なお、モジュールの編集、プロジェクトの構造の変更、コンパイルエラーの発生、 >参照設定の変更、デザインモードへの切り替え、コントロールを削除して [元に戻す] >を実行するなどのタイミングで変数が破棄される場合があります。 > >これは、そのタイミングでメモリ上に確保されているVBA の情報が破棄され、 >初期化を行ってから、その後の処理が実行されるためです。 > >補足 : この文書で説明する Public 変数とは、 >すべてのモジュール レベル変数および静的変数を指します。
ichinoseさんが言っていたのは、普通のデータはどっかに書込・保存が利くが、 オブジェクトはそうもいかないよねってことで、 アドインファイルに格納している、との事だったかも知れません。
「意図しないタイミング」で起きるといっているので、再現性のあるテストは難しい。
けど、ググると、実行途中にEndステートメントを書くと、破棄が起きるらしい。 なので、それでもichinose方式は無事かチェックしてみた。
隠居じーさんのアイデアに従って、test3実行後にtest4を実行
アドインファイル(pvtest.xlam) の ThisWorkbook(=v) Public cnt As Long Public ws1 As Worksheet
テストファイル(pvtest.xlsm) の 標準モジュール
Sub test3() Set ws1 = ThisWorkbook.Worksheets(1) Set v.ws2 = ThisWorkbook.Worksheets(1)
Debug.Print "Test3 実行" Call test5(ws1, "test3-xlsm") Call test5(v.ws2, "test3-xlam")
End '強制破棄を試みる
End Sub
Sub text4() 'test3終了後に実行 Debug.Print "Test4 実行" Call test5(ws1, "test4-xlsm") Call test5(v.ws2, "test4-xlam") End Sub
Sub test5(ws As Worksheet, oya As String) If ws Is Nothing Then Debug.Print oya & "のオブジェクトは破棄された" Else Debug.Print oya & "のオブジェクトは生きている" End If End Sub
<結果> Test3 実行 test3-xlsmのオブジェクトは生きている test3-xlamのオブジェクトは生きている
Test4 実行 test4-xlsmのオブジェクトは破棄された test4-xlamのオブジェクトは生きている
アドインの方は生きていましたー。
>ループカウンターに使うとエラーになります。??
ループカウンターに使う変数には制限があるんじゃないですか?
ヘルプを見ると
>counter 必ず指定します。カウンタに使う数値変数を指定します。 >配列変数およびブール型 (Boolean) に含まれる変数は指定できません
とか書いてありますので、書き漏れじゃないですかねぇ。 (そんなことをする人がいると思っていないでしょうし・・
(半平太) 2018/10/22(月) 17:46
(隠居じーさん) 2018/10/22(月) 18:19
>アドイン側の標準モジュールに記述すればループカウンターも正常作動なのですが >標準モジュールを使うと意味が無いのでしょうか。
すみません 何の意味か分かりません。
>ループカウンターにつきましては使えないとの理解で良いのでしょうか。
そう思ったのですが、何か別の切り口があるんでしょうか?
ループカウンタに使う変数は何でもいいって訳じゃない、と言うだけの認識なんですけども。
(半平太) 2018/10/22(月) 19:13
エラー内容を書いてるのに、誰もそれに触れてないのは気のせいでしょうか
コンパイルエラー”変数が必要です” なので、変数が破棄されたという問題ではなく、 そもそも実行すら出来てないということではないのでしょうか
そこで、 Sub test() v.cnt = 1000 MsgBox v.cnt Stop End Sub とし、ローカルウインドウを見てみると、 - : Module1 : : Module1/Module1 : : <変数なし> :
エラーどおり、変数がないようです
では、cntはどこにあるのかというと、
Sub test() Dim chk Set chk = v v.cnt = 1000 MsgBox v.cnt Stop End Sub
として、再度ローカルウインドウを見てみると、 - : chk : : Variant/Object/v (略) : CheckCompatibility : False : Boolean : cnt : 1000 : Long : CodeName : "v" : String (略) プロパティに混じってます
なら、プロパティを使うと同じエラーが出るか試してみます
Sub test3() For Range("A1").Value = 1 To 10 MsgBox Range("A1").Value Next End Sub
同じエラーが出ますね 型が違うだろとも言われそうなので、
: RevisionNumber : 0 : Long
確認用で、 Sub test4() v.RevisionNumber = 1 MsgBox v.RevisionNumber End Sub これは「コンパイルエラー:値の取得のみ可能なプロパティに値を設定することはできません。」
Sub test3() For v.RevisionNumber = 1 To 10 MsgBox v.RevisionNumber Next End Sub こちらは「コンパイルエラー:変数が必要です。」となります
プロパティはプロパティであって、変数とはみなされないのでしょう もっとも、自分の考え方が根本的に間違えていたら、話になりませんが (2u) 2018/10/22(月) 19:48
> コンパイルエラー”変数が必要です” > なので、変数が破棄されたという問題ではなく、
問題は2つなんです。1は大した問題じゃないですけど。
1.なぜコンパイルエラーになるのか?
2.上記1とは関係なく、意図しないタイミングで参照が破棄される対策として、 アドインブックの変数に保存する方法がワークするかどうか?
> プロパティはプロパティであって、変数とはみなされないのでしょう
私には理解不能です。
オブジェクトがメンバーとして持っている普通のスカラー変数は、 そのオブジェクトのプロパティですよ。 相容れないものじゃないです。
(半平太) 2018/10/22(月) 20:14
> プロパティはプロパティであって、変数とはみなされないのでしょう
これは正しい様な気がしてきました。
Dim v.cnt as ?
なんて書き方できないですから、「変数」と呼ぶのはおかしい。
2uさん 済みませんでした。 m(__)m
(半平太) 2018/10/22(月) 20:57
半平太さん >>すみません 何の意味か分かりません。 いえ、こちらこそ説明不足ですみません。
アドインを参照する方式だとpvtest.xlamの変数の定義場所は thisworkbookモジュールでも標準モジュールでも 意図しないタイミングで変数が破棄される対策に有効かどうかをお尋ね致しました。 2uさん詳しい解析ありがとうございます。 プロパティだとそうなるのですね、勉強になります。 γさんサイトのリンクありがとうございます。m(__)m
(隠居じーさん) 2018/10/22(月) 22:03
半平太さんのコードを拝借して、pvtest.xlamのthisworkbookモジュールの 変数定義をpvtest.xlamの標準 モジュールに書き換えて オブジェクト名を同じくvに変え実行した結果です。
pvtest.xlam (p) の標準モジュール (v) に
Option Explicit
Public cnt As Long Public ws2 As Worksheet
pvtest.xlsm の 標準モジュールに
Option Explicit Public ws1 As Worksheet Sub test3() Set ws1 = ThisWorkbook.Worksheets(1) Set v.ws2 = ThisWorkbook.Worksheets(1) Debug.Print "Test3 実行" Call test5(ws1, "test3-xlsm") Call test5(v.ws2, "test3-xlam") End '強制破棄を試みる End Sub Sub text4() 'test3終了後に実行 Debug.Print "Test4 実行" Call test5(ws1, "test4-xlsm") Call test5(v.ws2, "test4-xlam") Call counter_test End Sub Sub test5(ws As Worksheet, oya As String) If ws Is Nothing Then Debug.Print oya & "のオブジェクトは破棄された" Else Debug.Print oya & "のオブジェクトは生きている" End If End Sub Sub counter_test() For v.cnt = 1 To 3 Debug.Print v.cnt Next End Sub
結果です。 Test3 実行 test3-xlsmのオブジェクトは生きている test3-xlamのオブジェクトは生きている Test4 実行 test4-xlsmのオブジェクトは破棄された test4-xlamのオブジェクトは生きている 1 2 3
となりましたです。
(隠居じーさん) 2018/10/22(月) 22:33
あれー、なんで counter_test()の For v.cnt = 1 To 3 が旨くいっちゃうのー。
標準モジュールの場合、クラスモジュールじゃないので、v.cnt ってプロパティじゃないんですかね?
2uさんの見解待ちですね。
いずれにしても「test4-xlamのオブジェクトは生きている」だから、対策の有効性が濃厚ですね。
ところで、隠居じーさんは何故Counter変数に拘るんですか?
そんなに重要じゃないような気がするんですけども。
ループの途中でトラブって、再実行がシームレスで出来る方法、なんてのを考えているんでしょうか?
(半平太) 2018/10/22(月) 22:45
(隠居じーさん) 2018/10/22(月) 23:15
(隠居じーさん) 2018/10/22(月) 23:35
あれ? もう終わっちゃうんですか?
通常、ループ処理が途中で終わるなんてことは無いですよね?
そうなると、ループのCounter変数が
「グローバルである必要性」かつ 「破棄が心配になる事情」
がよく解からないんですけど・・
企業秘密なら無理にはお尋ねしませんが。
(半平太) 2018/10/23(火) 00:03
> 「グローバルである必要性」かつ
すみません。こっちについては、これが答えだったんですね。 ↓ >メインルーチンでループ回しあとはループの中から各サブルーチン呼び出しスタイルにすると
その時 、Counterは引数で受渡ししない、と理解しました。
(半平太) 2018/10/23(火) 09:13
>>あれ? もう終わっちゃうんですか?
いえ、とても勉強になりますので、使用上の留意点とか、
モジュールの違いとかお教えいただくことの方が多いとは思いますが
ご意見、ご感想等。。。大歓迎です。お礼が言いたくて(隠居じーさん) 2018/10/22(月) 23:35
となりました。
(半平太)さん 2018/10/23(火) 09:13につきましては
ご指摘の通りです。
(隠居じーさん) 2018/10/23(火) 09:30
pvtest.xlam (標準モジュール)変数定義 Option Explicit
Public cnt2 As Long Public ws2 As Worksheet
pvtest.xlsm 変数の定義とコード
Option Explicit Public ws1 As Worksheet Public cnt1 Sub test6() For cnt2 = 1 To 10 cnt1 = cnt1 + 1 Next End End Sub Sub test7() Debug.Print "xlsm = " & cnt1 Debug.Print "xlam = " & cnt2 End Sub
結果
xlsm = xlam = 11
でした。xlamの方は消えていません。
昨夜のループカウンタテストではENDをかけていませんでした (使えるかどうかのみテストでしたので) モジュールの指定無しでもといううか、普通に変数として使えました。^^
(隠居じーさん) 2018/10/23(火) 10:29
いや〜長い間エクセル使っていましたけど知りませんでした 別BOOKじゃなくても。 thisworkbookモージュールにパブリック変数を定義して 標準モジュールから参照すると変数が有りません。としかられます。wえ! 同じパターンの様ですu2さんがご指摘のプロパティなのでしょうか。 フォームモジュールではテストしていませんが、不思議ですね。 私が知らなかっただけでしょうか。A^^;
(隠居じーさん) 2018/10/23(火) 12:15
うん ? ↑ なにか混乱していますね ^^; すみません。 変数、スコープ、モジュール もう一度おさらいしてみます。 (隠居じーさん) 2018/10/23(火) 12:51
知らなかったです。
ループカウンターにその種の変数(プロパティ?)を使った経験自体ないです。
通常、定義したモジュール内にあるプロシージャのループで使うだけですからねぇ。
(半平太) 2018/10/23(火) 12:55
わたしも普段はループカウンタにオブジェクトモジュールのパブリック変数 を使ったことは有りませんでした。 そういえば思い出しましたが 何故かモジュール名から指定しなくては使えなかったですね。
オブジェクトモジュールのパブリック変数とは実は変数ではなくてオブジェクトモジュールの プロパティ?なのでしょうか。 「読込み、設定は出来るけど変数と同じようには(例、ループカウンタ)使えない。」なのでしょうか。 クラスモジュールでもなく標準モジュールでもないですね。 イベントプロシジャー以外は標準モジュールに書いた方が良い理由なのでしょうか 全て推測ですみません。
(隠居じーさん) 2018/10/23(火) 13:35
>オブジェクトモジュールのパブリック変数とは実は変数ではなくてオブジェクトモジュールの >プロパティ?なのでしょうか
なんか私には理解できない切り口なんですけど、変数とプロパティは相反する概念じゃないです。
当該オブジェクトがプロパティとして変数を持っているので、変数です。
ただ、ループカウンターとして使う変数には制限があるというだけです。
上で書きましたけど、「配列変数」は使えないとヘルプに明示されていましたよね? 他にも制限があるのだけども、MSが厳密に書かなかっただけだと思います。
(半平太) 2018/10/23(火) 14:01
>>当該オブジェクトがプロパティとして変数を持っているので、変数です。 >>ただ、ループカウンターとして使う変数には制限があるというだけです。 >>他にも制限があるのだけども、MSが厳密に書かなかっただけだと思います。 確かに。そぉかもしれませんね。 HELP見ました。 あと アドインブック使用の際、excel終了後 タスクマネージャで確認してもエクセルが残っている事はなかったです。 使用後のアドインBOOKでの定義変数はエクセル様がメモリ解放して下さっている との理解でよければ。どんどん使わせていただきたいと思っております。 今一度、レンジ、ディクショナリ等、オブジェクト変数でも試してみますです。 (隠居じーさん) 2018/10/23(火) 14:25
結構増えてるなぁ
今の問題は、標準モジュールオブジェクト名をv、その中に
Public cnt As Long
と書き、次のSubを実行した場合にv.cntがエラーにならない理由ですよね
Sub counter_test() For v.cnt = 1 To 3 Debug.Print v.cnt Next End Sub
それは、「モジュール名.変数名」という形式で モジュールで宣言された変数を呼び出しているからでしょう
・・・前回といってることが違う?
それは「変数の有効範囲」の話になります 以下、自分自身の確認とメモ書きもかねてまとめてみます 間違っていたらきっと指摘や訂正してくれるでしょう
第108回.変数の適用範囲(スコープ,Private,Public) https://excel-ubara.com/excelvba1/EXCELVBA408.html
この中の簡単なまとめには
・プロシージャー内で宣言した変数と引数は、そのプロシージャー内のみ使用可能 ・モジュールの先頭でDimまたはPrivateで宣言した変数は、そのモジュール内でのみ使用可能 ・モジュールの先頭でPublicで宣言した変数は、全てのモジュールで使用可能
とありますが、
標準モジュールとシートモジュールの違い https://excel-ubara.com/excelvba4/EXCEL251.html
の「■モジュールレベル変数」には以下のように書かれています
・標準モジュール:全て使用可能 ・ブックモジュール:Public変数は無効となりPrivate扱いとなる ・シートモジュール:Public変数は無効となりPrivate扱いとなる
ということは、ブックモジュールであるThisWorkbookモジュールに
Option Explicit Public cnt As Long
と書いても実際のところは
Option Explicit Private cnt As Long
として扱われるため、2018/10/23(火) 12:15の隠居じーさんさんのような結果になるのでしょう
ではcounter_test()の v.cnt がエラーにならない理由ですが、 第108回.変数の適用範囲(スコープ,Private,Public) の「変数の重複について」にこう書かれています (必要と思う部分だけ抜き出してますので、必要な方は上のアドレスからお読みください)
何も指定しなければ、自身の中で定義した変数が使われます。 Module1.i このように、モジュール名で修飾することで、「モジュールレベル変数」を使う事が出来ます。
複数のモジュールにある「モジュールレベル変数」が重複している場合は、 上記のように、モジュール名で修飾して使います。
これは、別の見方をすれば 「モジュール名で修飾することで、そのモジュールのPublic変数を呼び出すことが出来る」 と言うことなのでしょう
ここまで、簡単にまとめてみました (2u) 2018/10/23(火) 20:08
> これは、別の見方をすれば > 「モジュール名で修飾することで、そのモジュールのPublic変数を呼び出すことが出来る」 > と言うことなのでしょう
と言うことは、これは厳密な正確性を持った表現ではないと解釈されますね? ↓ > ・ブックモジュール:Public変数は無効となりPrivate扱いとなる
(半平太) 2018/10/23(火) 20:49
こういう記事↓を読んでも「何となく分かった様な気はするけどさぁ...」レベルの者が失礼します ^^;
連載! とことん VB: 第 14 回 Visual Basic 固有の「モジュール」(Module) の役割 in VB.NET
https://code.msdn.microsoft.com/windowsdesktop/14-Visual-Basic-Module-2c407099
VBのモジュールはオブジェクト指向に不要? - @IT
http://www.atmarkit.co.jp/fdotnet/vbcheer/vbcheer07/vbcheer07.html
きっと本格的な開発環境に慣れている人々にとって、 単に「モジュール」って表現している所は「標準モジュール」を意味しているのでしょうね。 標準モジュールだけは、クラスとオブジェクトの関係から切り離された存在に見えます。 「みんなのひろば」みたいな「場所」でしかない存在というか。
無いアタマで自分なりに解釈してみると、 ・クラスモジュール ← インスタンス作らないと使えない ・オブジェクトモジュール ・シート、ブックモジュール ← 既存のインスタンス扱い? ・ユーザーフォーム ← クラスとしても使えるインスタンス? (逆か?) ・標準モジュール ← インスタンス作れないし、インスタンスでもない。静的クラス(なんじゃそりゃ)とも違うらしい
という感じに受け止めてます。
「モジュール名.変数名」という書き方も 標準モジュール上では「モジュールのメンバー」(「プロパティ」という表現もちょっと違うのかな? と。)である時点で 「共有メンバー」であり、「(特定の)オブジェクトのメンバー」とは意味合いが違うのかも知れません。
・・・というタダの感想でした。失礼しました。
ちなみに「まさかそれは無いよね?」と思って念の為やってみましたが、 標準モジュール上にPublic Property Get/Letでプロパティを作っておいて、 別モジュールからループカウンタとしてそのプロパティを使うことは、やはり出来ませんでした。 (コンパイルエラー:変数が必要です)
(白茶) 2018/10/23(火) 23:11
2uさん、白茶さん、リンク並びにご解説ありがとうございます 変数か。制限付き変数か。はたまたプロパティなのか。。。^^; 何故ループカウンターでは変数が有りませんエラーなのか。。。 季節は秋が深まる中エクセル様の謎も深まるよ〜な(何バカな事言ってる!) 議論は深まるなか、とりあえずオブジェクトが残らないか?テスト 先輩先生が既にお使いの様なので残るはずはないと思いましたが。せっかく作ってみましたので 諸先輩の前に出せるようなコードでは有りませんが、アップいたします。 このよ〜な組み方の是非はともかくパブリック変数テストみたいな感じです。 シート名Sheet1に適当に結合セルを作成後お試しください、突っ込み大歓迎 ^^v 実行後タスクマネージャで見てもexcel様の残骸は見当たりませんでした。
pvtest.xlam 標準モジュール v
Public rr As Range Public r As Range Public D, buf() Public sh01 As Worksheet
pvtest.xlsm 標準モジュール
Option Explicit Sub main() 'マージセル調査再構築 On Error GoTo stperr Call start_main Call set_range For Each r In rr Call data_make Next Call write_data Call dest Exit Sub stperr: On Error GoTo 0 Call dest End Sub Private Sub start_main() Set D = CreateObject("Scripting.Dictionary") End Sub Private Sub set_range() Set sh01 = Worksheets("Sheet1") Set rr = sh01.UsedRange ReDim buf(1 To rr.Count, 1 To 2) End Sub Private Sub data_make() Dim n As Long If r.MergeCells Then If Not D.exists(r.MergeArea.Address) Then n = D.Count + 1 buf(n, 1) = r.MergeArea.Address(0, 0) D(r.MergeArea.Address) = n Else n = D(r.MergeArea.Address) End If buf(n, 2) = r.MergeArea.Interior.Color End If End Sub Private Sub write_data() Dim cnt As Long, y As Long: y = 1 sh01.Copy With ActiveSheet .UsedRange.Clear .Cells(y, 1) = "Sub xxx()" If D.Count <> 0 Then For cnt = 1 To D.Count y = y + 1 .Cells(y, 1) = "range(""" & buf(cnt, 1) & """).Merge" y = y + 1 .Cells(y, 1) = "range(""" & buf(cnt, 1) & """).Interior.Color=" & buf(cnt, 2) & "" Next End If .Cells(y + 1, 1) = "End Sub" End With End Sub Private Sub dest() D.RemoveAll Erase buf Set rr = Nothing Set r = Nothing Set sh01 = Nothing End Sub (隠居じーさん) 2018/10/24(水) 07:50
すこしきになりましたので ^^ 気弱な老人のいいわけです 隠居じーさん) 2018/10/24(水) 07:50の >>季節は秋が深まる中エクセル様の謎も深まるよ〜な(何バカな事言ってる!) は私自身のことを私自身が叱っています。決して、貴重なお時間をおさき戴き、 様々なご意見、ご感想をお寄せいただいている諸先生の事ではありません。 誤解を招くような表現で申し訳ありませんでした。 原因はどうであれ、 ループカウンターとしては使えない事実を知ることが出来た事はすごく私自身の勉強になりました。 このスレにお書込み頂いた皆様には、深く深く感謝致しております。 今後ともよろしくお願いいたします。
(隠居じーさん) 2018/10/24(水) 13:18
https://excel-ubara.com/excelvba4/EXCEL251.html って「エクセルの神髄」さんでしたか。
以前、その人の書いた内容について、この板で質問があり、関連個所を読みに行ったことがあるんですが、 でたらめな事やる人だなぁと思ったことがあり、余りいい印象は持っていないです。
そうなると、これは嘘と思う。それが本当なら、コンパイル時点でエラーになってしかるべきだと思います。 ↓ >■モジュールレベル変数 >・標準ジュール:全て使用可能 >・ブックモジュール:Public変数は無効となりPrivate扱いとなる >・シートモジュール:Public変数は無効となりPrivate扱いとなる
「用語的には、若干の独自補正を加えています」と言っているので、「嘘」は言い過ぎかも知れないけど。
Public、Privateの判定以前の問題、つまり、そもそも外部から相手にされていない。 v.(ヴィ、ドット)と打って初めて、Public か Privateの判定に入る。
隠居じーさんのコードをみましたけど、一気通貫に終わっちゃうプロシージャですよね。
何かのタイミングで破棄される心配は無いと思うんですけどねぇ・・ 企業秘密なら無理に事情はお聞きしないですけども。
(半平太) 2018/10/24(水) 16:20
こんばんは ^^ 感想。有難うございます。 >>企業秘密なら無理に事情はお聞きしないですけども。 ハンドルの通りで。。。隠居の身でして 決して秘密など御座いませんです。はい。 ただ、危険性が有るのなら少しでも回避したいな〜と。^^; ループカウンターは今回パブリック変数としては使いませんでしたが。 コード書きながら、便利なのは便利なのですが 扱いには気を付けないと見つけにくいバグ発生の原因になりかねないなぁとの実感は有りました。 オブジェクトも同じですが複数回使い回すのは避けた方が良いのでしょうね。 サンプルコードは以前、半平太さんが作っておられたシート解析プログラムを拝見し、感嘆しておりました。 (難しくて理解できていません。「バラバラのアドレスを纏める」処理が凄いですね) 自分でも作成出来ないかと挑戦中です。とりあえずマージセルのみつくってみました。。。 お恥ずかしい限りです。私のスキルではまぁこんな程度です。^^
private扱いでもモジュール名指定でアクセス出来る、出来ないと ループカウンタで使える、使えないは別の様な気がするのですが どうなんでしょうかね。 。。。m(__)m でわ (隠居じーさん) 2018/10/24(水) 17:36
>ただ、危険性が有るのなら少しでも回避したいな〜と。^^;
何か勘違いされているんじゃないかという気がしてきたんですけど・・
プログラムが完全に終了したあと、次にオペレーターが処理を再開するようなプログラムにおいて 前回使ったモジュールレベルの変数がまだ有効に残っている保証がないですよ、っていう事であって、 一気通貫に走り終わるプログラムにそんな危険性はないです。
>Private扱いでもモジュール名指定でアクセス出来る、出来ないと
問題になっている状況がちょっと分からないです。
「Private扱いでもモジュール名指定でアクセス出来る」と言う具体例を挙げて頂けませんか?
>ループカウンタで使える、使えないは別の様な気がするのですが
ループカウンタは、わざわざ「ループカウンタ変数」という用語を使っているくらいで、 普通の変数と違う制約があることが伺い知れるので、ループカウンタに割り当てて エクセルに怒られたら素直に従うだけだと、私としては思っています。 (理屈を考える気がしないです。ヘルプもそんなに充実した書き方をしていないので)
(半平太) 2018/10/24(水) 19:24
> 以前、その人の書いた内容について、この板で質問があり、関連個所を読みに行ったことがあるんですが、 > でたらめな事やる人だなぁと思ったことがあり、余りいい印象は持っていないです。 > そうなると、これは嘘と思う。それが本当なら、コンパイル時点でエラーになってしかるべきだと思います。
なんでかなー、と思っていたらそこのサイトは信用したくないってことでしょうか ちょっと気になったので検索してみたのですが、ここも信用できないって言われそうですね・・・
https://excelwork.info/excel/varscope/
でもまあ、シートモジュール・ブックモジュールの Public 宣言が有効だったら 使い物にならないような気がしますね
(2u) 2018/10/24(水) 19:29
https://excelwork.info/excel/varscope/
こんなこと言っている箇所は無さそうですけど? ↓ >■モジュールレベル変数 >・標準ジュール:全て使用可能 >・ブックモジュール:Public変数は無効となりPrivate扱いとなる >・シートモジュール:Public変数は無効となりPrivate扱いとなる
(半平太) 2018/10/24(水) 19:42
半平太さん >「Private扱いでもモジュール名指定でアクセス出来る」と言う具体例を挙げて頂けませんか?
たぶんこれは単に >>・ブックモジュール:Public変数は無効となりPrivate扱いとなる >>・シートモジュール:Public変数は無効となりPrivate扱いとなる
を受けての表現だと思いますよ^^;
(エクセルの神髄さんの言う)Private扱い(となってしまったPublic変数)でもモジュール名指定でアクセス出来る、 (ホントにPrivate扱いならそもそもアクセス)出来ない(ハズだよね)と ループカウンタで使える、使えないは別(の問題)
と読み替えてみました ^^;
まぁ、真意は隠居じーさんさんに聞いてみないと分かりませんが、 文脈的にはそんな感じに聞こえます。
(白茶) 2018/10/24(水) 20:23
白茶さん 代弁、有難う御座います。その通りです。
>>何か勘違いされているんじゃないかという気がしてきたんですけど・・ うう、^^ その通りだと思います。そぉだったのですね。 私が書いているコードくらいだと問題は無いのですね。 おっしゃっておられるようなコードを書く時の対処方法を教えていただき、 有難うございました。
(隠居じーさん) 2018/10/24(水) 20:49
白茶さん
ありがとうございます。納得です。
議論が繋がっていたんですね。
半分くらいしか分かっていないので、私の頭の中では全然別の事になっちゃっていました。
私としては、親元(?)を書かない限り、変数の存在すら無視された状態であり、 Public性・Private性 を云々する以前の状態だと思っています。
なので、こう言う表現は語弊があると思っています。 ↓ >・ブックモジュール:Public変数は無効となりPrivate扱いとなる >・シートモジュール:Public変数は無効となりPrivate扱いとなる
(半平太) 2018/10/24(水) 21:18
>私が書いているコードくらいだと問題は無いのですね。
サンプルに上がったものは問題ないですが、
イベントが絡むコードで、モジュールレベルの変数を設定している様な時は、 大抵(発生頻度は低いものの)この危険が発生していると思います
初回、ボタンをクリックすると、(モジュールレベルのRange変数がNothingなら) アクティブセルに色を付ける、と言うコードを作ったとします。
初回クリックで、アクティブセルに色を付けて、プログラムは一旦終了します。
次に同じボタンをクリックすると、前回色を付けたセルの下に色を付けると言う仕掛けだと、 前回色を付けたセルを覚えておく必要があります。 多分、モジュールレベルの変数にセットすることになると思います。
通常、モジュールレベルの変数はプログラムの実行が終わっても初期化されないので、 下方へ色づけを続けることが出来ます。
でも、予期しないタイミングで前回セルの情報が消えていたら、 またアクティブセルに色を付けに行っちゃいます。
(なら、色付けしたセルをアクティブにしておけよ、と言う話は無しで。あくまで例なので)
でも滅多に起きないので、Q&Aではそんなこと気にする回答者は居ないと思います。 (自分の仕事でもないですし、仮にそこまでやっても正統な評価を受けられるかどうかも怪しい)
(半平太) 2018/10/24(水) 23:20
今更ながら「当たり前だろ」って事を確かめてみました。 Module1、Module2、ThisWorkbook、Sheet1、Sheet2それぞれに
Public v As Long を宣言し、 Module3で
Sub test() Debug.Print Module1.v, Module2.v, ThisWorkbook.v, Sheet1.v, Sheet2.v End Sub
こんなのを書いてみても、とりあえずコンパイルエラーは出ませんね。
但し「Module1.」を付けなければ「コンパイルエラー:名前が適切ではありません v」が出ます。 「v」だけだと、どのPublic変数なのかを一意に特定できなくなってしまったからでしょうね。 経験からこれは恐らく「Module1.vなのかModule2.vなのかどっち?」という事だと予想します。 では Module2のPublic v As Longを削除したらどうか。
Sub test() Debug.Print v, Module1.v, ThisWorkbook.v, Sheet1.v, Sheet2.v v = 1 Debug.Print v, Module1.v, ThisWorkbook.v, Sheet1.v, Sheet2.v End Sub
やはり「v」だけでも、コンパイルエラーは出ません。Module1.vに1が入りました。 では、 Module1のPublic v As Longも削除したらどうか。
Sub test() Debug.Print v, ThisWorkbook.v, Sheet1.v, Sheet2.v End Sub
「コンパイルエラー:変数が定義されていません」が出ます。
いずれのモジュールでも変数の宣言部分は同じですが、 WorkbookとSheetは「モジュール名.変数名」という書き方じゃないとアクセスできない →変数の持ち主から呼び出さないと見えてこない 正に >親元(?)を書かない限り、変数の存在すら無視された状態 ですね。 対して 標準モジュールは、標準モジュール全体で変数名が重複してなければ「モジュール名.」を省略できる。 そしてループカウンタに「モジュール名.変数名」と書いても何だか通っちゃう。
「オブジェクトに属するPublic変数をループカウンタとして使うことは出来ない」というのが本来の仕様なのであれば、 標準モジュールは「オブジェクトではない」あるいは「ただのオブジェクトではない」と言えるのかも。 やはり「標準モジュール」という「場所」の特性なのでしょうね。
あれ? >Public変数は無効となりPrivate扱いとなる この表現をうまく釈明できる言葉が出て来ないものかとやってたハズだったのですが、結局出なかった... orz
(白茶) 2018/10/24(水) 23:32
おはようございます ^^ 白茶さん 詳細なテスト、ご説明、本当に有難うございます。 標準、シート、BOOK、各シートの特徴が良くわかります。 半平太さん、貴重なご教授、解りやすいご解説 ありがとうございます。 >>でも滅多に起きないので、Q&Aではそんなこと気にする回答者は居ないと思います。 >> (自分の仕事でもないですし、仮にそこまでやっても正統な評価を受けられるかどうかも怪しい)
かもしれませんね ^^; シートのイベントプロシージャはよく使います。 良く簡単なデータベースもどきは作るのですが、 モジュールレベルの変数使用の場合 入力待ち受け画面 → 分岐(新規登録、修正登録、削除、取消)戻る→、入力待ち受け画面 の様な流れを繰り返す処理の場合も「危険あり」に該当しますでしょうか。
(隠居じーさん) 2018/10/25(木) 07:38
> モジュールレベルの変数使用の場合 > 入力待ち受け画面 → 分岐(新規登録、修正登録、削除、取消)戻る→、入力待ち受け画面 > の様な流れを繰り返す処理の場合も「危険あり」に該当しますでしょうか。
そう言われましても単純に判断つきません。
待ち受け画面からスタートする時、 前回処理した時に設定した変数の値が初期化されていないことを期待して プログラムを組んでいるなら危険ありです、MSの説明と同じです。m(__)m
変数の値が何になっていようとも、スタートしてから新規に値を設定しながら 進める作りなら何も危険は無いです。 (同じ器を使っているだけであり、前のカスが残っていてもそれを捨て去って器だけ使うプログラム)
(半平太) 2018/10/25(木) 10:23
>>そう言われましても単純に判断つきません。 ごもっともです。分かりやすいご説明、有難う御座います。 何となく解ってきたような気がいたします。イベント処理も含めますと。。。 コードの再点検してみます。^^;
(隠居じーさん) 2018/10/25(木) 11:04
現在使用中のものはざ〜と点検しました。案外モジュールレベル変数は使っていませんでした。 ここでまた何かのおり、私がアップしたコードでそのようなものを見つけられ、めにあまるようでしたら 突っ込んでやってください ^^;。。。 本当にお世話になり有難うございました。とても勉強になりました。 お書込み頂いた皆様、有難うございました。 m(__)m (隠居じーさん) 2018/10/25(木) 15:45
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.