Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


6475 / 13644 ツリー ←次へ | 前へ→

【44997】隠しメソッド/プロパティの作り方 TOSHI 06/12/9(土) 12:57 質問[未読]
【45005】Re:隠しメソッド/プロパティの作り方 ichinose 06/12/9(土) 20:29 発言[未読]
【45010】Re:隠しメソッド/プロパティの作り方 TOSHI 06/12/9(土) 23:14 質問[未読]
【45015】Re:隠しメソッド/プロパティの作り方 再投... ichinose 06/12/10(日) 8:44 発言[未読]
【45020】Re:隠しメソッド/プロパティの作り方 再投... TOSHI 06/12/10(日) 11:42 お礼[未読]
【45022】隠しメソッド/プロパティの作り方 再質問 TOSHI 06/12/10(日) 12:38 質問[未読]
【45031】Re:隠しメソッド/プロパティの作り方 再質... ichinose 06/12/10(日) 16:40 発言[未読]
【45036】ありがとうございました TOSHI 06/12/10(日) 18:38 お礼[未読]

【44997】隠しメソッド/プロパティの作り方
質問  TOSHI  - 06/12/9(土) 12:57 -

引用なし
パスワード
   はじめまして、TOSHIといいます。

今、あるユーザー向けのクラスモジュールを作成してます。
標準モジュールから、そのクラスのインスタンスからメソッドや
プロパティを参照するのですが、インスタンスの後に"."を記述して
その後Publicのメソッドやプロパティの一覧が出ますが、この一覧
に出さずに、直接記述して標準モジュールから参照する方法は有りますで
しょうか。

クラス”CTEST”というものがあった場合で

'以下CTEST内のメソッド

Public sub Func1() as Long
 MsgBox "Func1!"
end Sub

Public sub Func2() as Long
 MsgBox "Func2!"
end Sub


このCTESTを標準モジュールで

Public testc as New CTEST


sub test()

tesstc.  '<---- このときに表示される一覧からFunc2
      '   表示はしませんが、直接記述する事で実行したいです。


end sub


済みません、どなたかわかる方いましたら教えて頂けますでしょうか。

【45005】Re:隠しメソッド/プロパティの作り方
発言  ichinose  - 06/12/9(土) 20:29 -

引用なし
パスワード
   ▼TOSHI さん:
こんばんは。

>今、あるユーザー向けのクラスモジュールを作成してます。
>標準モジュールから、そのクラスのインスタンスからメソッドや
>プロパティを参照するのですが、インスタンスの後に"."を記述して
>その後Publicのメソッドやプロパティの一覧が出ますが、この一覧
>に出さずに、直接記述して標準モジュールから参照する方法は有りますで
>しょうか。
へえ、こんなことがVBAで出来るのでしょうかねえ??
私の投稿以降にやり方があったなら、以下の記述は忘れてください。

代替案として、新規ブックにクラスモジュールを二つ作成します
(Class1、Class2)

Class1のモジュールに

'==================================================
Option Explicit
Private cls As Class2
'==================================================
Public Sub Func1()
 MsgBox "Func1!"
End Sub
'==================================================
Property Get 隠し() As Object
  Set 隠し = cls
End Property
'==================================================
Private Sub Class_Initialize()
  Set cls = New Class2
End Sub
'==================================================
Private Sub Class_Terminate()
  Set cls = Nothing
End Sub


Class2のモジュールに
'==================================================
Option Explicit
Public Sub Func2()
 MsgBox "Func2!"
End Sub


として、

標準モジュールに以下のコードを記述する時、
'=================================================
Option Explicit
Sub test()
  Dim クラス As Class1
  Set クラス = New Class1
  クラス.Func1 'ここでは、Func1はメンバーリストに入っている
  クラス.隠し.Func2 'ここでは、「隠し」はリストに表示されるが
'           Func2は表示されない 
  Set クラス = Nothing
End Sub

コードを追ってみて頂ければ、理由は分かると思います。

他に方法がなかったら、これで代替できるか 検討してみてください。

【45010】Re:隠しメソッド/プロパティの作り方
質問  TOSHI  - 06/12/9(土) 23:14 -

引用なし
パスワード
   ▼ichinose さん:
ありがとうございます。
この方法は、目からうろこ状態でした、レイトバインディング
による手法で、clsにタイプライブラリ情報を持たせない手法なんですね。


贅沢な希望なのですが、わたしの方の希望としましては、
2つ有ります。
 1.Fucn2からClass1のPrivate関数をCallしたい
 2.できれば1つのClassで実現したい

1に関してはichinoseさんの方法を使用させていただきまして
イベント追加し実現できました
そのコードが以下になります。

2ですが、私の方で、attribute を使用して一つのClassで
隠蔽する方法がないか調べてました。
海外のHPに”Hidden Property”というのが有りまして
クラスモジュールをエクスポートした後に隠蔽したいコレクション
アイテムプロパティを以下のように書き換え、再度インポートすれば
よいような事が書いてあり私もこれをヒントに、コレクションでなく任意の
Publicメンバ関数やプロパティに利用できるか試してみましたがだめでした。
以下が、そのコレクションの隠蔽?になります。
(済みません私もよく判らないので日本語がおかしいです。
 申し訳ないです)
この側面から隠しメソッドができないかなと考えて、いろいろ数値
を変えたり、違うAttributeを探して試したましがギブアップしてしまいました。
Public Property Get Items( _
) As IUnknown

'Attribute Items.VB_UserMemId = -4
'Attribute Items.VB_MemberFlags = "40"

' this property allows you to enumerate
' this collection with the For...Each syntax
Set Items= m_colItems.[_NewEnum]

End Property


以下が、1を実現したコードです。
'----------------Class1--------------------------------
Option Explicit

Private WithEvents cls As Class2
'==================================================
Public Sub Func1()
 MsgBox "Func1!"
End Sub
'==================================================
Property Get Raw() As Object
  Set Raw = cls
End Property
'==================================================
Private Sub Class_Initialize()
  Set cls = New Class2
End Sub
'==================================================
Private Sub Class_Terminate()
  Set cls = Nothing
End Sub

Private Sub Func2Private()
  
  MsgBox "Func2Private!"

End Sub

Private Sub cls_Func2()
  Call Func2Private
End Sub

-------------------------------------------------

'----------------Class2--------------------------------
Option Explicit
Public Event Func2()


Public Sub Func2()
  
  RaiseEvent Func2
  MsgBox "Func2!"
  
End Sub
'------------------------------------------------------

'----------標準モジュール-------------------------------
Dim クラスAs New Class1

Sub test()
  クラス.Func1 'ここでは、Func1はメンバーリストに入っている
  HDW.Raw.Func2 'イベント経由でClass2からClass1のプライベイト
         '関数をCall
End Sub
'------------------------------------------------------------

【45015】Re:隠しメソッド/プロパティの作り方 再...
発言  ichinose  - 06/12/10(日) 8:44 -

引用なし
パスワード
   おはようございます。
>この方法は、目からうろこ状態でした、レイトバインディング
>による手法で、clsにタイプライブラリ情報を持たせない手法なんですね。
まっ、そういうことです。

>贅沢な希望なのですが、わたしの方の希望としましては、
>2つ有ります。
> 1.Fucn2からClass1のPrivate関数をCallしたい
> 2.できれば1つのClassで実現したい
なるほど・・・、ちょっと考え方を変えてみませんか?
(以下に記述する内容はExcel2000以降のバージョンで実現出来ます)

「上記のふたつ条件をどうして満たしたいのか」

という基本を押さえましょう!!

> 2.できれば1つのClassで実現したい

これは、隠蔽化が前回の私のコードでは出来ていないですからネ!!
Class2のインタンスを作成すれば、
「隠し.」以下のメンバーも見えてしまいますからね

結論から言えばクラスを二つにするということは変えられません。
が、しかし、隠蔽化することはできます。

隠蔽化を実現するためにクラスモジュールを特定のプロジェクトに
記述し、このプロジェクトを使って隠蔽化します。

> 1.Fucn2からClass1のPrivate関数をCallしたい

これも プロジェクトの外からは、Private関数なるものが
呼び出し出来ないようにすれば良いですね!!


まず、新規ブックに対して以下の操作を行なって下さい。

クラスモジュールを二つ作成します。

Class1

Class1を作成したら、プロジェクトエクスプローラーにて作成した
Class1を選択してください。この状態でF4キーを押してClass1の
プロパティウインドーを表示させて下さい。

このClass1のプロパティに「Instancing」というプロパティがあります。
既定値が「1-Private」になっていますから、
これを「2-PublicNotCreatable」に変更してください。

これでClass1の設定は出来ました。

Class1のコードです。

Option Explicit
Private cls As Class2
'==================================================
Public Sub Func1()
 MsgBox "Func1!"
End Sub
'==================================================
Property Get Raw() As Object
  Set Raw = cls
End Property
'==================================================
Private Sub Class_Initialize()
  Set cls = New Class2
  cls.set_parent = Me
End Sub
'==================================================
Private Sub Class_Terminate()
  Set cls = Nothing
End Sub
'==================================================
Friend Sub Func2Private()
'↑ここがポイント
  MsgBox "Func2Private!"
End Sub


次にClass2です。こちらのプロパティは、既定値のままでよいです。
変更しないで下さい。
Class2のコードです。

'=================================================
Option Explicit
Private parent As Class1
'=================================================
Property Let set_parent(obj As Object)
  Set parent = obj
End Property
'=================================================
Public Sub Func2()
  parent.Func2Private
End Sub


最後にThisworkbookのモジュールに

'=================================================
Option Explicit
Function set_class1() As Class1
  Set set_class1 = New Class1
End Function


上記の設定でプロジェクトとして、隠蔽化します。

プロジェクトエクスプローラーにて、このブックを選択して下さい。

選択した状態で 右クリック---「VBAProjectのプロパティ」を
クリックして「プロジェクトプロパティ」というダイアログを表示させます。

「全般」タブの「プロジェクト名」にユニークな名前を付けます。

ここでは、「test_project」と命名して、OKをクリックして下さい。
一度、このブックを保存します。

保存ブック名は何でも良いですが、適当なフォルダにTest1.xlsという名前で
保存してください。

クラスモジュールはこのtest_projectを介して使用するようにします。

上記のブックは閉じないで下さい。


別に新たに新規ブックを作成します。Book2とします(既定名)。

プロジェクトエクスプローラーにて、このブックを選択して下さい。

選択した状態で 「ツール」---「参照設定」をクリックして
「参照設定」というダイアログを表示させます。

一覧にさっき命名した「test_project」がありますから、チェックを入れて
OKをクリックします。


このBook2の標準モジュールに
以下のコードをコピーではなく、実際にキーパンチしてみて下さい。
(コメントは除いて・・・)

'=========================================================
Option Explicit
Sub test()
  Dim クラス As test_project.Class1
'    test_project. の時点でClass1は見えるが
'               class2は見えない
  Set クラス = test_project.ThisWorkbook.set_class1
  With クラス
    .Func1  'Func1は、メンバーとして見えるが、
'         Func2Privateは見えない 
    .Raw.Func2 '.Rawは、メンバーとして見えるが、
'          .Raw. でFunc2は見えない  
    End With
  Set クラス = Nothing
End Sub


いかがですか?
test_projectというプロジェクトとして、隠蔽化することにより、
TOSHI さんが掲げた条件を結果として
満たしていませんか?

尚、私は、このtest_projectをアドインとして登録して
運用することが多いです。

検討して見てください

【45020】Re:隠しメソッド/プロパティの作り方 再...
お礼  TOSHI  - 06/12/10(日) 11:42 -

引用なし
パスワード
   ▼ichinose さん:
おはようございます。
TOSHIです。

詳細まで教えていただいて感謝してます。
大変勉強になりました。
この方法ですと一つのBook or Addinを渡すだけなので
目的に十分達成してます。又、プロジェクトの保護を入れる
ことでコードの機密性も出ますし、一石二鳥ですね。
ありがとうございました。


PS:VBのメソッド隠蔽属性→AttributeのVB_MemberFlags = "40"はVBAでは
  サポートしてないようです。

【45022】隠しメソッド/プロパティの作り方 再質問
質問  TOSHI  - 06/12/10(日) 12:38 -

引用なし
パスワード
   ▼ichinose さん:
こんにちは
先程は、ありがとうございました。

済みません、更に質問が有ります。
実は、隠蔽するメソッドがかなり有り、それを使用する
特別なユーザーは、隠蔽メソッドを覚えておくか、忘れた場合は
実際のクラスモジュールを開いてメソッド名を確認して記述する必要が
有ります。


そこで以下のような事ができないかいろいろ試してみましたが
うまくいきませんでした。

クラス.Raw.XXX.ooo
XXXを入力して、"."を記入するとClass2のメソッド一覧(ooo)
が表示される。

そこでClass2に以下を追加してみたのですが、Class2のPublicメソッド/プロパティの一覧表示は無理でした。
またClass2のプロパティ「2-PublicNotCreatable」をしてみてもだめでした。
'========Class2====================
'以下のXXXプロパティを追加
Property Get XXX() As Class2
  Set XXX = Me
End Property


結局その機能を満たす為以下のように
しました。
これだと、クラス2変数や、オブジェクトブラウザ
から隠し用のClass2のメソッド(XXX)がわかってしまいますので、
クラス.Raw.XXX
を記述されCallされてしまいます。

XXXの隠しメソッドを特定ユーザが覚えていればいいのですが、
今のところXXXを10種〜20種用意しようと思ってますので
すこし利便性が悪いかなと思って悩んでます。
済みませんいろいろお時間とらせてしまって教えていたいたでのすが
この方法の解決方法が有りましたら教えていただけないでしょうか。

宜しくお願いいたします。


Sub test()
  Dim クラス As test_project.Class1
  Dim クラス2 As test_project.Class2
  Set クラス = test_project.ThisWorkbook.set_class1
  With クラス
    .Func1  'Func1は、メンバーとして見えるが、
'         Func2Privateは見えない 
    Set クラス2 = .Raw.XXX '
    クラス2. '<-ここで隠蔽したメソッド一覧が見える 
    End With
  Set クラス = Nothing
  Set クラス2 = Nothing

End Sub

【45031】Re:隠しメソッド/プロパティの作り方 再...
発言  ichinose  - 06/12/10(日) 16:40 -

引用なし
パスワード
   こんにちは。

>先程は、ありがとうございました。
>
>済みません、更に質問が有ります。
>実は、隠蔽するメソッドがかなり有り、それを使用する
>特別なユーザーは、隠蔽メソッドを覚えておくか、忘れた場合は
>実際のクラスモジュールを開いてメソッド名を確認して記述する必要が
>有ります。

見えても困るし、見えなくても困るし・・・。

最終的には、隠蔽メソッドに関するドキュメントを残すということだと
思います。

他には、

クラス.Raw.mem__help flnm

としたら、指定されたファイル名にメンバーの説明を記述するとか・・・。


とこんなことしか思い浮かびませんでした。

【45036】ありがとうございました
お礼  TOSHI  - 06/12/10(日) 18:38 -

引用なし
パスワード
   ▼ichinose さん:
こんばんわ、TOSHIです。

メソッドを隠蔽できるだけでも有りがたいです。
いろいろ無理な質問に答えていただいて
助かりました。

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

6475 / 13644 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free