- ベストアンサー
ActiveX EXEのオブジェクトに渡したオブジェクトが微妙
またまた微妙な質問ですみません。 ------- ActiveX EXEプロジェクト Class Hoge Public Sub Moge(lst) Dim Cast As ListBox MsgBox TypeName(lst) 'ListBoxと表示される Set Cast = lst 'ここがエラー Cast.List(2) = "hogehoge" 'キャストはできないがVariant型のままのアクセスは可能 End Sub ------- 標準EXE Class Form1 (List1を配置) Dim X As New Hoge Private Sub Form_Load() X.Moge List1 End Sub ----- このように、アウトプロセスのオブジェクトにフォームのコントロールを渡しました。 引数の型をAs ListBoxにしたかったのですが、それだとまずそこで型が一致しないといわれます。 しようがないのでVariantで引数を宣言し、渡した後にキャストしようと思ったのですが、そこでも型が一致しないといわれます。 TypeName関数は "ListBox" を返すし、Variant型のままメンバにアクセスすることはできるのですが、ListBox型の変数に代入することだけできないのです。 別プロセスのオブジェクトには、オブジェクトの参照は渡せないのでしょうか?
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
リストボックスをオブジェクト変数にセットして、何をしたいのでしょうか? それがわかった方が、求める動きが可能かもしれません。 別プロセスでオブジェクトを渡すのは無理かと思います。 もしできるとしたら、オブジェクトのハンドルを取得し、オブジェクト変数の領域を確保。そこに代入という方法が思いつきますが、領域確保が思うようにならないVBでは落ちると思います。 ただリストボックスの選択している場所を得たいとか、選択させたいとか、そういう操作なら別プロセスなら、ハンドルだけで操作する方法もあります。 結局結末は何がしたいのでしょうか?
その他の回答 (8)
- TAGOSAKU7
- ベストアンサー率65% (276/422)
順次はいつも使用していないので、わかりません。。。^^;
- TAGOSAKU7
- ベストアンサー率65% (276/422)
アクセス=管理できている とは言いません。 先にも挙げたように LB_GETCOUNT 'ListCountの取得 LB_SELECTSTRING 'ListIndexの指定 LB_GETTEXTLENとLB_GETTEXT 'テキスト取得 LB_RESETCONTENT 'Clear LB_GETCURSEL 'ListIndexの取得 と言う定数があります。別にオブジェクトの型にセットできなくても、処理は可能です。 だから別にActiveXでなくても、アクセスができます。 値の設定・情報の取得ができることが、管理できているとは言うことにはなりません。 例えば、List1.ListIndex = 5とするとLB_SELECTSTRINGが投げられます。 VBはCで言うマクロを行っているだけです。 ListCountやClearなども一緒です。 管理できているから可能というわけでなく、ハンドルさえ取得したらできることです。 >Dim X As 外部ActiveXEXEのクラス >Set X = New 外部ActiveXEXEのクラス >とした時点で、Xが外部のプロセスの情報を持つことができるはずで、すでに持っていると考えられないでしょうか? ActiveXを自分(本体EXE)の子として扱う場合は話が別です。それが売りのActiveXなのですから・・・・ それができないなら、ActiveXじゃなくて、標準EXEでもいい事になります。 しかし外部EXEでオブジェクトを参照可能なのは、自分がインスタンスを作成したActiveXだけです。 A.EXE(標準) B.EXE(ActiveXAから派生) C.EXE(標準) D.EXE(ActiveXCから派生) AからBは管理できる CからDは管理できる AからDは無理 という事が言えます。
お礼
色々とアドバイスありがとうございます。 ちょっとリストから離れますが、やっぱり同じエラーを出すコード。 ------ client.exe Public Sub main() Dim Thread1 As New Class1 Dim Thread2 As New Class2 Dim Thread3 As New Class3 Thread1.Init Thread3 Thread2.Init Thread3 Thread3.Init Thread1, Thread2 'ここでエラー End Sub ------ server.exe ------ Class1, Class2(本当は同じじゃないけど) Private C3 As Class 3 Public Sub Init(c As Class3) Set C3 = c End Sub ------ Class3 Private C1 As Class1, C2 As Class2 Public Sub Init(cc1 As Class1, cc2 As Class2) Set C1 = cc1 Set C2 = cc2 End Sub ------ このようなコードが、なぜか完全コンパイルなしだと、通ることがあります。 >しかし外部EXEでオブジェクトを参照可能なのは、自分がインスタンスを作成したActiveXだけです。 どうもこれが原因みたいな気がします。 ひとまず、オーバーヘッドがあってもいいので、なんとか目的を達成できるようにがんばります。 私の微妙な疑問に付き合ってくださって、どうもありがとうございました。
- TAGOSAKU7
- ベストアンサー率65% (276/422)
質問: >ActiveX EXEのオブジェクトに渡したオブジェクトが微妙 したい事: >Variant型のままメンバにアクセスるとオーバーヘッドがあるので、ListBoxにちゃんとキャストしてから呼びたいといいたいのです。 回答:#4より >もし >Dim Cast As ListBox >と宣言して、この変数に別プロセスのリストボックスをセットできるとしたら、 ・・・・ >イベントを取得できないVBのオブジェクトを、コントロールの型の変数にセットするのは、皆無かと思います。 ということなのですが、、、 もう一度言います。 VBのコントロールの型(as listbox,as commandbuttonなどなど)は、他のプロセスでコントロールの受けでは使用できないと思います。 VBが内部でプロセス監視などをしていると思いますが、他のプロセスからはそこまでのサポートを行っていないからという状況のようです。 #4で「リストボックスのイベントが必要ですか?」と質問したわけではありません。「リストボックスのイベントを拾えない他プロセスのリストボックスを、コントロールの型にはセットできない」と言ったつもりなのですが・・・ それと、、、やはり題意からそれた部分ですが・・・ 本体EXE(リストボックスあり) ActiveXEXE(NET SENDを使用するEXE、本体EXEのリストボックスにステータスを送る) という作りですよね?(違っているかもしれませんが、そうだと思って、勝手に書きます。) ユーザが本体EXEで操作し、裏でActiveXEXEが何個も起動して進捗状況やステータスを本体EXEに送りたいということですよね? この2EXE間のやり取りには、お約束が定められていないと、非常に厳しいように思います。 本体EXEがActiveXを起動したときプロセスIDを取得しておく。 ActiveXがリストボックスに記す時、自プロセスIDを冠につけるとかすると、多少は融通が利くと思いますがどうでしょうか?
お礼
>そうだと思って、勝手に書きます。 これは意図したとおりです。 >この2EXE間のやり取りには、お約束が定められていないと、非常に厳しいように思います。 えーと、お約束はすでにVBが定義済みなのでは? ActiveX EXEは別プロセスと言えど、ActiveX DLLのコンポーネントとほとんど同じように扱うことができるではないですか。 ActiveX EXEがエクスポートしたコンポーネントは、クライアントで参照設定することにより、別プロセスであると言うことを除けば、普通にメンバにアクセスできます。 プロセスIDなどのやり取りは、すでに変数内部でVBが勝手に行っているような気がするのですが・・・。 Dim X As 外部ActiveXEXEのクラス Set X = New 外部ActiveXEXEのクラス とした時点で、Xが外部のプロセスの情報を持つことができるはずで、すでに持っていると考えられないでしょうか?
- TAGOSAKU7
- ベストアンサー率65% (276/422)
だんだん題意からそれてきた気が・・・^^; ListBoxの型は無理というのはOKだったのでしょうか? まぁそれはそれとして、管理者以外はたぶん見てないだろうから、まぁいいかw NetApiBufferSend とは NetMessageBufferSendの事だったのですね? それとも別にあるのかな? http://vbvbvb.com/jp/gtips/0251/gNetMessageBufferSend.html ↑こんな感じで使用されているのですよね? 整理したいのですが、二つのEXEがあり、 一つはActveXを呼ぶEXE 一つはActveX(EXE)※こちらで送信する ということですよね? それと私が#4で述べたのは、この二つのEXEの連携部分であって、他のマシンへの送信方法ではありません。「別プロセスのコマンドボタンを押す 」は完全に別プロセスです。 オーバーヘッドが起こるのは作りの問題のように思えるのですが・・・ ActivX側でインスタンスが作成するたびに、それまでのオブジェクトを破棄させてはいませんか?全体的なソースの公開がないと、これ以上の発言は難しいです ーー;
お礼
>だんだん題意からそれてきた気が・・・^^; いえ、それてるつもりはないのですが・・・。 Variant型のままメンバにアクセスるとオーバーヘッドがあるので、ListBoxにちゃんとキャストしてから呼びたいといいたいのです。 ごめんなさい、最初からこれを言えばよかったんですよね。 >NetMessageBufferSendの事だったのですね ごめんなさい、いつもマップ関数を通していたので勘違いしていました。 >こんな感じで使用されているのですよね? ちょっと違います。 UNICODE関数を呼ぶときはいつもバイト配列を渡していますから。 Declare Function NetMessageBufferSend Lib "netapi32.dll" ( _ ByVal servername As Long, _ msgname As Byte, _ fromname As Byte, _ buf As Byte, _ ByVal buflen As Long _ ) As Long Dim usr() As Byte, from() As Byte, msg() As Byte usr = "ゆーざー" + vbNullChar from = "じぶん" + vbNullChar msg = "めっせいじ" + vbNullChar ret = NetMessageBufferSend(0, usr(0), from(0), msg(0), Len("めっせいじ") * 2) >整理したいのですが、二つのEXEがあり・・・ということですよね? はい、そのとおりです。 >オーバーヘッドが起こるのは作りの問題のように思えるのですが・・・ やはり、関数を呼び出すために、文字列のハッシュから関数ポインタを見つけ出すのは・・・。 実際に気持ち悪いと思います。 PerlやJAVAScriptとかは全部文字列→関数で呼んでいますが、VBはスクリプトではないですし。 >全体的なソースの公開がないと じつは、まだUMLもどきで設計段階で、実際のソースはぜんぜん書いていません。 しかし、Variant型とListBox型の変数を用意して、ループの中でそれぞれのメンバにアクセスするコードを書いてみると、明らかな違いは現れます。 Dim x As ListBox, y, n as long, t As String Set x = Form1.List1 Set y = Form1.List1 For n = 0 To 100000 t = x.List(0) Next For n = 0 To 100000 t = y.List(0) Next
- TAGOSAKU7
- ベストアンサー率65% (276/422)
>NetApiBufferSend は使用したことがない事と、文献が周りに無いのでコメントできませんが。。。 それとCallByName関数も初めて知りました。 しかしCallByName関数の必要性がよくわかっておりません。 ちなみに私の場合は、他のプロセスのコントロールはほとんどAPIで制御します。 以下の定数をSendMessage関数で使用すると、リストボックス構造持ったオブジェクトの属性設定/取得が可能です。 LB_GETCOUNT 'ListCountの取得 LB_SELECTSTRING 'ListIndexの指定 LB_GETTEXTLENとLB_GETTEXT 'テキスト取得 LB_RESETCONTENT 'Clear LB_GETCURSEL 'ListIndexの取得 他にリストボックスのハンドルを取得さえできれば、必要なことはできると思います。 他のプロセスとの連携を図るなら、DDE通信やWinSockを使用した通信もあると思うのですが。。。 もしくは、本体のフォームにコマンドボタン二つ用意(成功/失敗)を用意しておいて、NetApiBufferSendを使用している方から、終了するたびにボタンを押してもらうとか? Sock通信 http://oshiete1.goo.ne.jp/kotaeru.php3?q=155606 DDE通信 http://oshiete1.goo.ne.jp/kotaeru.php3?q=233790 別プロセスのコマンドボタンを押す http://oshiete1.goo.ne.jp/kotaeru.php3?q=199357
お礼
何度もアドバイスありがとうございます。 NetApiBufferSendはDOS窓でnet send ユーザー名 メッセージとやるのと同じ関数です。 CallByName関数は、実行時に呼び出すメンバを決定できる関数で、ユーザーが呼び出すクラスのメンバを指定できたりします。 関数をハッシュで呼び出してるようなものです。 これはVariant型やObject型、Control型にオブジェクトの参照が入っているとき、そのメンバにアクセスするときに暗黙に使われているはずです。 通常は関数はポインタを使って呼び出されるでしょうが、これを使うと文字列からハッシュなどで対応している関数を探さなければならず、多用したときのオーバーヘッドが気になるのです。 WinSockでの通信は考えましたが、やはりオブジェクト指向言語ですし、遠回りなのでこの方針は変えたくないです。 >本体のフォームにコマンドボタン二つ用意・・・ net send通信を別スレッドでバックグラウンドにやってもらいたいので、これは目的にかなっていません。 APIはある程度使いますが、できればVB内部の仕様で行きたいです。 特に構造体+APIの使用は、コード量増加につながりますし。
- TAGOSAKU7
- ベストアンサー率65% (276/422)
>時間のかかるAPI とは? もしかしてSendMessageで行っているからとか? PostMessageで送ることで回避というわけにはいきませんか? それと調査した結果を述べます。推測部分が多いのですが、勘弁してください。 ウォッチウインドウで表示される型は、あくまで型です。 だからといって、その型にセットできるわけではないようです。 もし Dim Cast As ListBox と宣言して、この変数に別プロセスのリストボックスをセットできるとしたら、 WithEvents Cast As ListBox でもセットできることになります。 そうなると、別プロセスのリストボックスのイベントを拾うことができることになります。 おそらく、VBがそのようなことをサポートしていないので、コントロールの型での宣言ができないのではないでしょうか? 別プロセスのリストボックスだから、派生させた元が違うということが大きく影響します。 VB内部では、派生させた瞬間にプロセス監視を行っているはずです。同一プロセス内では、WithEventsでのコントロール型の変数にセットしたら、そのプロセス監視を新たに起こすのではなく、使いまわしていると思います。 別プロセスだと、そこまで融通が利かないと思います。 ただし、受けをVariantにしていると、構造とメモリエリアを取得します。その構造がVBのリストボックスなので、TypeNameはきちんと表示されるのだと思います。 そのリストボックスのリストインデックスや、リストの値、リスト件数などはプロセス監視をしなくてもできる部分なので、問題なくリストを操作することができるものだと思います。 イベントを取得できないVBのオブジェクトを、コントロールの型の変数にセットするのは、皆無かと思います。 それと気になったので・・・ クラスファイルのメンバにあっても、通常は問題ないです。
お礼
>もしかしてSendMessageで行っているからとか? 違います。 NetApiBufferSendです。 ネットワークでNETBIOS over TCP/IPを使うようになってから、NetApiNameAdd/Delも含めて、これらのAPIの同時使用をすると、関数が必ず失敗するという症状があらわれるようになったため、これらの関数をシングルスレッドに任せることになったのです。 かといって1つ1つの関数が終了するまで2秒間など止まられては、ユーザーインターフェースは機能しなくなってしまいますから。 >そうなると、別プロセスのリストボックスのイベントを拾うことができることになります。 Variant型のままアクセスしたりはできるんです。 Variant型のままアクセスすると、CallByName関数が暗黙のうちに使われると思うのですが、これだと実行時に関数名、プロパティ名の解決が行われるので、何度も使う場合オーバーヘッドが気になるのです。 べつにリストボックスのイベントがほしいわけではありません。 リストボックスのプロパティとメソッドにアクセスしたいだけなのです。 そのたびに名前解決を行っているのは、ちょっと問題があると思ったので。 >受けをVariantにしていると、構造とメモリエリアを取得します Variant型だから別プロセスのメモリ位置まで同時に保持しているというのは理解しました。 まぁ、別プロセスのメモリ内容にアクセスしているということ自体、今回驚きなんですが。
- Ulrika
- ベストアンサー率45% (59/129)
#1です。 コントロールは普通フォームオブジェクトの下のオブジェクトとして使うもの、ということで クラスのメンバに持っていても表示されないのだと思います(ということに今気がついた)。 時間がかかるAPIを呼んだ時の処理ということであれば、もう1つ別の監視&巡回型の Exeを噛ませてもいいかも。その中にタイマーを仕込んでおいて、一定時間ごとに 処理が終わったかどうか見に行くのは? Public WithEvents aaa As Timer ←こんなので宣言。 DoEventでとりあえず次を処理してて、APIが終わったらイベントを発生させるような。 質問にあるリストボックスを受取ってやりたいこととは違うかもしれませんが…。
お礼
返事が遅くなってすみません。 >もう1つ別の監視&巡回型のExeを噛ませてもいいかも すでにそのとおりです。 別の監視EXEがActiveX EXEなのです。 そこでAPIを読んでAPIから制御が返ってきたら、受け取っているListBoxに対して、処理を行います。 WithEventsははじめて知りました。 試してみますが、タイマーはもうできるだけユーザーインターフェースを含むスレッドで使うと、イベントが発生した時にIME入力などがキャンセルされてしまうので、できるだけ使いたくないです。
- Ulrika
- ベストアンサー率45% (59/129)
こんにちは。 Public Sub Moge(lst) と宣言しているのを Public Sub Moge(lst as ListBox) とやってもダメですか? 呼ぶ方と呼ばれる方の宣言が同じでないとうまく参照できなかったような記憶があります。 ListBoxがControlという宣言と見なされて受取っているからSetできないのではないかと。
お礼
そうすると、Mogeを呼び出す時点で型が違うといわれてしまいます。
お礼
Variantのままlst.List(5)というアクセス方法はできるのですが、受け取ったリストボックスの参照に対して、非常に多くの動作をしたいので、Variant型で実行時バインドされると、ちょっと気持ちが悪いのです。
補足
コントロールではなくクラスなら普通に渡すことができました。 しかし、コントロール変数をメンバに持っていても、エディタでその変数のメンバを表示しようとしても出ませんでした。 具体的にやりたいことですが、制御を返すのに時間がかかるAPIを読んでしまった場合、VBではタイマーを使ったりしても、どうしてもプログラム全体が止まってしまいます。 通常はそのような関数は別スレッドで呼ぶべきなのでしょうが、VBにはスレッドがありませんので、ActiveX EXEを使って、擬似スレッドにしようと思ったのです。