4

UserControlを使用するVB6で記述されたプロジェクトがあります。プロジェクトは、OCXが登録されている場合は正常に実行されますが、同じプロジェクトを並べて実行すると、エラーが発生します。

コントロールが静的にロードされている(フォームに前に追加されている)限り、問題なくコントロールを使用できますが、新しいコントロール(プロパティまたはメソッド)の使用時にフォームに動的コントロールを追加すると、次のエラーが発生します。

オブジェクトはこのプロパティまたはメソッドをサポートしていません

このエラーは次のように再現できます。

  1. VB6でOCXプロジェクトを作成する
  2. ユーザーコントロールを追加する
  3. DoSomethingコントロールなどにメソッドを追加します
  4. exeプロジェクトを作成する
  5. フォームにコントロールを追加します。例:UserControl1
  6. イベントコールでDoSomething
  7. 次のように動的にロードします。

    Dim y As Control
    UserControl1.DoSomething        '<-------- CASE(1) THIS IS ALLRIGHT!'
    Set y = Controls.Add("Project1.UserControl1", "y")
    y.DoSomething                   '<---- (CASE 2) THIS WILL FAIL USING SXS'
    

WinDbgのエラーを追跡しましたがIDispatch::GetIDsOfNames、2番目のケースで呼び出されたときに失敗します。

何か案が?!

編集:私の悪い、ここにマニフェストがあります。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">

<assemblyIdentity name="client.exe" version="1.0.0.0" type="win32" processorArchitecture="x86"/>

<file name="Project1.ocx">
 <comClass
     clsid="{C8CF7991-A8F2-4360-9404-03C9A052C245}"
     description="Project1.UserControl1"
     tlbid="{47853CCC-7BE6-4377-9C82-38A0B7755F65}"
     threadingModel="apartment"
     miscStatusContent="recomposeonresize,cantlinkinside,insideout,activatewhenvisible,setclientsitefirst"
     progid="Project1.UserControl1"/>
 <typelib
     tlbid="{47853CCC-7BE6-4377-9C82-38A0B7755F65}"
     version="1.0"
     helpdir=""
     flags="control,hasdiskimage"/>
</file>

<comInterfaceExternalProxyStub 
     iid="{0E4F313E-7EF3-4FE6-9591-9F7D2D819AEE}"
     name="UserControl1"
     proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"/>
<comInterfaceExternalProxyStub 
     iid="{53307849-4F14-4A59-B0CA-DE4950CE499D}"
     name="UserControl1"
     proxyStubClsid32="{00020420-0000-0000-C000-000000000046}"/>

</assembly>
4

2 に答える 2

4

簡単な答え:これはVB6の既知の問題です。「Controls.Add」ステートメントは、サイドバイサイドでは機能しません。代わりに「Load」ステートメントを使用してみてください。

長い答え:ProgIDを使用してコントロールを作成している場合でも、VB6はコントロールのCLSIDを実行可能ファイルにコンパイルします。「Control.Add」を実行すると、CLSIDが同じであることが確認されます。理由を聞かないでください、これは触れないほうがいい謎です。同時に、win32を並べて(.Netを並べて表示するのではなく-別のトピック)、複数のマニフェストで使用されている同じProgIDを処理できるように準備する必要があります(アクティベーションコンテキスト間でフリップフロップを使用する場合)。たとえば)、ProgIDごとに新しい一時的なCLSIDを内部的に生成します。最後に、CLSIDFromProgIDを呼び出すと、一時的なCLSIDが取得されます。次にCoCreateInstanceを呼び出すと、正常に機能します。sxsはCLSIDを尊重します。しかし、どこか(レジストリ、内部テーブル)でCLSIDを探しに行くと、それは見つかりません。そして、CLSIDFromProgIDを呼び出して受信したCLSIDが内部テーブルにあるかどうかをチェックするVB6プログラムが登場します。失敗。

于 2011-04-01T23:41:15.950 に答える
2

これは、マニフェストと互換性のないVBマジックのケースです。この問題は、ユーザーコントロール参照を使用したVBの動作に起因します。変数を強く暗くしても、As UserControlこの参照のメソッド/プロパティへのアクセスは遅れます!VBは、参照される各ユーザーコントロールに拡張クラスを作成して、一般的なメソッド(SetFocus、Moveなど)を公開します。そのため、Dimを実行すると、コントロールのtypelib内の参照としてではなく、継承されたクラスへAs UserControlの参照としてコンパイルされます。の自動生成されたラッパー。UserControlVBControlExtenderUserControl

CurlandのAdvancedVisualBasic 6の本でユーザーコントロールの章を見つけてから私がしていることは、Direct User ControlsVBにラッパーを使用しないように強制するカスタムtypelibを作成することです。基本的には次のようになります。

[
  uuid(GUIDHERE-0000-1111-2222-2B5E1A72D6BF),
  version(1.0),
  helpstring("Direct User Controls Typelib 1.0")
]
library <<mytypelib>>
{
    importlib("stdole2.tlb");
    importlib("C:\\WINDOWS\\system32\\COMCTL32.ocx");
    importlib("C:\\WINDOWS\\system32\\COMCT232.ocx");
    importlib("C:\\WINDOWS\\system32\\shdocvw.dll");
    ...

    typedef [public] ComctlLib.ImageList                DirectImageList;
    typedef [public] ComctlLib.ListView                 DirectListView;
    typedef [public] ComctlLib.ProgressBar              DirectProgressBar;
    typedef [public] ComctlLib.Slider                   DirectSlider;
    typedef [public] ComctlLib.StatusBar                DirectStatusBar;
    typedef [public] ComctlLib.TabStrip                 DirectTabStrip;
    typedef [public] ComctlLib.Toolbar                  DirectToolbar;
    typedef [public] ComctlLib.TreeView                 DirectTreeView;

    typedef [public] ComCtl2.Animation                  DirectAnimation;
    typedef [public] ComCtl2.UpDown                     DirectUpDown;

    typedef [public] SHDocVw.WebBrowser                 DirectWebBrowser;
    ...
}

私のプロジェクトでは、メソッドを早期に呼び出して、「直接」参照を保持します。私はControls.Addこのように使用します

Dim oCtl As DirectXxx
Set oCtl = pvCastVBControlExtender(Controls.Add(PROGID_Xxx, sName)).Object

キャスティングヘルパーはこのようなものです

Private Function pvCastVBControlExtender(oCtl As VBControlExtender) As VBControlExtender
    Set pvCastVBControlExtender = oCtl
End Function

このスニペットは、VBIDE、登録済みコントロール、および登録なしコントロールの3つのケースで期待どおりに機能します。

于 2011-04-02T08:57:20.320 に答える