tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
[ツリー表示へ]  [ワード検索]  [Home]

タイトル Re: エクセルの非表示シートを削除したい
投稿日: 2022/05/20(Fri) 23:36
投稿者魔界の仮面弁士
> 独学でvb6を始めて1年です。
1998年9月に発売されたのち、2008年4月8日に延長サポートの期間を終えた化石環境ですね…。
自分はすっかり使わなくなってしまいました。

VBA との互換性は高いですが、Microsoft の公式資料も色々見れなくなっているので
細かい情報が今となっては拾い集めにくくなっているかもしれません。


> エクセルVBAで確認し
Excel は 32bit 版ですか? 64bit 版ですか?


> 参照設定もMicrosoft DAO 3.6 object Libraryしか設定できない環境です。
どういう意味でしょうか。参照設定の一覧にそれしかないという状況は考えにくいですし…
Excel VBA の参照設定に現れる内容と、VB6 の参照設定の内容に差がある、ということでしょうか。

仮に Office 側が 32bit 版だったとしても、基本ライブラリは別物なので、
既定の参照設定ライブラリの内容は一致しないのが普通です。
(もちろん、両方で使えるライブラリもあります)


なお、VB6 から Excel を操作する場合には、参照設定で
"Microsoft Excel xx.x Object Library" を使うことが一般的です。

ただし、インストールされている Office がストアアプリ版の場合は、VB6 からの操作が
できないことがあります。その場合は、デスクトップ アプリ版の Office に変更してみてください。
https://curio-shiki.com/blog/office/office-storeapps-to-desktop-version


> Sub 非表示のワークシートをすべて削除する()
VB6 においては、全角文字や半角カナでの命名は推奨されていません。
公式サイトの情報は、かなり昔に失われているので、以下は Internet Archive へのリンクですが:

KB418924: Visual Basic でプロジェクト名に日本語の文字を使用できない
https://bit.ly/3LB5MTs

上記を見ると、『変数、定数、およびプロシージャの名前』などに
『日本語の文字を使用することができません』と明確に記されています。

実際には使えてしまうことが多いのですが、特定の OS バージョンで、
一部の文字が問題を起こす事象は、過去に何度か報告されていました。

Grapecity: コントロールの名称に長音記号「ー」を使用できない場合がある
https://dev.grapecity.co.jp/support/kb/detail.asp?id=30479

まぁ VB6 に限らず、Office VBA の世界でも問題が報告されていたりはするのですが。
https://social.msdn.microsoft.com/Forums/ja-JP/4e6223e2-34d0-4a5f-bb61-109bc28040b6/windows-10-1249612540124721251912531-2004-201973847712391?forum=officesupportteamja


ちなみに VB.NET では、この制限が撤廃されています。
KB921451: Visual Studio .NET 以降の各プログラミング言語と共通言語ランタイムで識別子に日本語の文字を使用できます
https://bit.ly/3PvQT89


>  If MsgBox("非表示のワークシートをすべて削除していいですか?", _
>   vbYesNo + vbDefaultButton2) = vbNo Then Exit Sub
本来は「+ 演算子」ではなく、「Or 演算子」で結合すべきですね。


>  Application.DisplayAlerts = False
上記は VBA の構文ですね。VB6 でこの記述は NG です。

Excel VBA にとっての「Application」とは、今まさに操作中の自分自身を指し示しますが、
VB6 側にとってみれば、どの Excel インスタンスのことなのか曖昧です。そのため、
 Dim ExcelApp As Excel.Application
 Set ExcelApp = New Excel.Application
 ExcelApp.Visible = True
などの変数を用意しておき、この変数を通じて
 ExcelApp.DisplayAlerts = False
などと記述せねばならないのです。ご注意ください。
https://support.microsoft.com/ja-jp/topic/da8e586a-b2ab-371f-1245-aad6f37e68b6

Excel Object Library を参照設定している場合は文法上、変数なしでいきなり
 Application.DisplayAlerts = False
と書けてしまうのですが、これは「グローバル オブジェクトへの参照」という状態となり、
オブジェクト解放がうまくいかなかったり、期待動作しなくなるなどといった、
誤動作の原因となることが知られています。

この点は、このサイト(VBレスキュー)でも注意書きがありますね。
http://hanatyan.sakura.ne.jp/vb6/excel01.htm


>  Dim sh As Worksheet
>  For Each sh In Worksheets
これも NG。

『For Each sh In Worksheets』という表現は、VBA であれば
「For Each sh In ThisWorkbook.Worksheets」相当であると判断されますが、
VB6 は Excel 上で動いているわけでは無いため、いきなり Worksheets とだけ書かれても、
どのワークブック上の Worksheets なのかが明確になりません。

先程の Application の場合と同様、こちらも
 Dim ExcelBook As Excel.Workbook
 'Set ExcelBook = ExcelApp.Workbooks.Add()
 Set ExcelBook = ExcelApp.Workbooks.Open("C:\Test\Example.xlsx")
のように、Workbook 型の変数を受け取ってから、
 For Each sh In ExcelBook.Worksheets
のようにして、「どのワークブック上の Worksheets なのか」を明確にします。

あるいは、Worksheets のための変数も追加して
 Dim ExcelSheets As Excel.Sheets
 Set ExcelSheets = ExcelBook.Worksheets
 For Each sh In ExcelSheets
のように書いても良いですね。


>   If sh.Visible = xlSheetHidden Then sh.Delete
Visible プロパティが返す値は
 xlSheetVisible (または True)
 xlSheetHidden (または False)
 xlSheetVeryHidden
の 3 種類です。
https://www.relief.jp/docs/excel-vba-xlsheetveryhidden-xlsheethidden.html

もし、今回の「非表示シートの削除処理」において、
xlSheetHidden だけでなく xlSheetVeryHidden も削除対象とする場合は、
 If sh.Visible <> xlSheetVisible Then
のように記述した方が良いかも知れませんね。


> For Each sh In Worksheets
>  If sh.Visible = xlSheetHidden Then sh.Delete
For Each によるループの最中に、対象のコレクションの数が
増減するような操作を行うことは避けた方が良いでしょう。
列挙順に影響を与えてしまうかもしれませんので。

仮に今は問題なくても、Office のバージョンによっては、
異なる動作になってしまう可能性が無いとも言い切れないと思います。

下記は Worksheets ではなく Range をループさせる場合の話ですが、
本件の問題点が具体的に解説されています。
https://docs.microsoft.com/ja-jp/office/troubleshoot/excel/use-for-each-next-loop-to-delete-cell


そのためこのようなケースでは、多少手間ではあっても
(案1) コレクションの末尾から先頭に向かって、インデックス指定で列挙する
(案2) コレクションの各要素の名前を最初に集めておき、その名前を使って削除する
といった処理を行った方が安全ではないでしょうか。

'【案1】の例
For n = ExcelBook.Worksheets.Count To 1 Step -1
 Set sh = ExcelBook.Worksheets(n)
 If sh.Visible = xlSheetHidden Then
  sh.Delete '末尾から削除していけば、残りのインデックスがずれることもない
 End If
Next


'【案2】の例
'あらかじめ、ワークシート名の一覧を作っておく
Dim targets As VBA.Collection
Set targets = New VBA.Collection
For Each sh In ExcelBook.Worksheets
    targets.Add sh.Name
Next
'その一覧を通じて削除するのであれば、削除しても列挙順には影響を与えない
Dim vnt As Variant
For Each vnt In targets
 Set sh = ExcelBook.Worksheets(vnt)
 If sh.Visible = xlSheetHidden Then
  sh.Delete
 End If
Next
Set targets = Nothing

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。