6

C# で機能する ActiveX コントロールを作成できません。成功せずにそうするために、チュートリアルに従ってみました。

このコードを含むサンプル クラス ライブラリ プロジェクトを作成します。

namespace AACWCSurvey
{
    [ProgId("Prisoner.PrisonerControl")]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public class Class1
    {
        public Class1()
        {
            MessageBox.Show("FIRETRUCK!!!");
        }
    }
}

次に、次の手順を実行しました。

  1. プロパティ => アプリケーション => アセンブリ情報 => アセンブリを COM 可視にする
  2. ビルド => COM 相互運用に登録する TRUE (チェック済み)
  3. アセンブリの強力な名前を作成 (署名)
  4. プロジェクトをビルドする
  5. regasm MyDll.dll /tlb /codebase

  6. Prisoner.PrisonerControltstcon32 で見えない=(

私のOSはWinXP x86です。


UPD: VBScript から動作します:

Dim objJava
Set objJava = WScript.CreateObject("Prisoner.PrisonerControl")

しかし、tstcon32 には表示されません。

4

3 に答える 3

2

Prisoner.PrisonerControl コントロールを使用して実際の記事を読むと、名前付きのサブキーControlがコントロール GUID を持つキー内に作成されます。

{9DEA5F06-E324-31A7-837B-D0F3BDE91423}キーを作成するGUIDを備えた私のマシンで

HKEY_CLASSES_ROOT\CLSID\{9DEA5F06-E324-31A7-837B-D0F3BDE91423}\Control

コントロールが に表示されるようにしtstcon32ます。そして、それの有無にかかわらず、ActiveXはjavascriptに使用できます

var x = new ActiveXControl("Prisoner.PrisonerControl");

実際には、システムでテストするために、javascript の実行とレジストリ パスの両方で Windows と戦わなければなりませんでした。これは x64 マシンですが、それは別の話です。

于 2011-10-10T13:14:18.943 に答える
2

COM サーバーは作成しましたが、tstcon32.exe で実行できる、はるかに複雑な COM オブジェクトである ActiveX コントロールは作成していません。

インターフェイスの束を実装する必要があります。重要なものは IOleObject と IOleWindow です。ActiveX ホストとの必要なネゴシエーションを実行し、可視ウィンドウを作成できるインターフェイスの種類。Winforms Control クラスを作成するのが最善の策です。

于 2011-10-10T13:22:38.570 に答える
1

外部で文書化されている関連手順は次のとおりです。これは、いくつかの説明を省略して要約されていますが、必要な手順は省略されています。

この例は、2008 年 11 月 25 日の Garry Trinder による記事Using Managed Controls as ActiveX Controlsにも非常によく似ており、この記事のメモもいくつか含めました。

Windows フォーム コントロールを ActiveX コントロールとして公開する

この記事では、.NET の外部で Windows フォーム コントロールを利用する方法について説明します。

コントロールを書く

  1. Visual Studio 内から新しいコントロール プロジェクトを作成します。私の例はすべて C# ですが、VB.NET も使用できます。

[Garry の記事では、「まず、マネージ ユーザー コントロール プロジェクト (Windows フォーム クラス ライブラリまたはコントロール ライブラリ プロジェクト) を作成します。ユーザー コントロール デザイナーを使用して、(好きな標準コントロールを使用して) カスタム ユーザーコントロールを好きなように設計します。」 ]

  1. コントロールなどをフォームに追加し、コードなどを入れます。

  2. 次の using 句を追加します...

using System.Runtime.InteropServices;
using System.Text;
using System.Reflection;
using Microsoft.Win32;
  1. クラスに属性を付けて、ProgID を取得できるようにします。生成されるため、これは厳密には必要ありませんが、ほとんどの場合、明示的に指定するのが最善です。

[ProgId("Prisoner.PrisonerControl")]
[ClassInterface(ClassInterfaceType.AutoDual)]

これにより、ProgID が割り当てられ、公開されるインターフェイスが「AutoDual」であることも定義されます。これにより、クラスのすべてのパブリックで非静的なメンバーからデフォルト インターフェイスが作成されます。これが望ましくない場合は、他のオプションのいずれかを使用してください。

  1. アセンブリが COM 相互運用に登録されるように、プロジェクトのプロパティを更新します。

VB.NET を使用している場合は、厳密な名前のアセンブリも必要です。不思議なことに、C# ではそうではありません。コンパイラや CLR の機能ではなく、環境の機能のようです。

  1. 次の 2 つのメソッドをクラスに追加します。

[ComRegisterFunction()]
public static void RegisterClass ( string key )
{ 
  // Strip off HKEY_CLASSES_ROOT\ from the passed key as I don't need it
  StringBuilder sb = new StringBuilder ( key ) ;
  sb.Replace(@"HKEY_CLASSES_ROOT\","") ;

  // Open the CLSID\{guid} key for write access
  RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(),true);

  // And create the 'Control' key - this allows it to show up in 
  // the ActiveX control container 
  RegistryKey ctrl = k.CreateSubKey ( "Control" ) ; 
  ctrl.Close ( ) ;

  // Next create the CodeBase entry - needed if not string named and GACced.
  RegistryKey inprocServer32 = k.OpenSubKey ( "InprocServer32" , true ) ; 
  inprocServer32.SetValue ( "CodeBase" , Assembly.GetExecutingAssembly().CodeBase ) ; 
  inprocServer32.Close ( ) ;

  // Finally close the main key
  k.Close ( ) ;
}

RegisterClass 関数は、ComRegisterFunction に関連付けられています。この静的メソッドは、アセンブリが COM Interop に登録されるときに呼び出されます。ここで行っているのは、「Control」キーワードをレジストリに追加し、さらに CodeBase エントリを追加することだけです。

CodeBase は興味深いものです - .NET コントロールだけではありません。これは、コードが見つかる場所への URL パスを定義します。これは、この例のようにディスク上のアセンブリである場合もあれば、どこかの Web サーバー上のリモート アセンブリである場合もあります。ランタイムがコントロールを作成しようとすると、この URL がプローブされ、必要に応じてコントロールがダウンロードされます。これは、.NET コンポーネントをテストする場合に非常に便利です。.EXE と同じディレクトリ (など) に常駐するという通常の注意事項が適用されないためです。

[ComUnregisterFunction()]
public static void UnregisterClass ( string key )
{
  StringBuilder sb = new StringBuilder ( key ) ;
  sb.Replace(@"HKEY_CLASSES_ROOT\","") ;

  // Open HKCR\CLSID\{guid} for write access
  RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(),true);

  // Delete the 'Control' key, but don't throw an exception if it does not exist
  k.DeleteSubKey ( "Control" , false ) ;

  // Next open up InprocServer32
  RegistryKey inprocServer32 = k.OpenSubKey ( "InprocServer32" , true ) ;

  // And delete the CodeBase key, again not throwing if missing 
  k.DeleteSubKey ( "CodeBase" , false ) ;

  // Finally close the main key 
  k.Close ( ) ;
}

2 番目の関数は、クラスが登録されていない場合に追加されたレジストリ エントリを削除します。

これで、コントロールをコンパイルしてテストする準備が整いました。

Garry のブログからの追加メモ:

[The] 追加のレジストリ エントリ: ControlMiscStatusTypeLibおよび Version[作成可能].REGスクリプトを使用しますが、通常は、登録/登録解除時に呼び出される関数を記述する方が適切です

彼は、レジストリ キーについて詳しく説明しています。

Control空のサブキーです。TypeLibTypeLib の GUID にマップされます (これは、assemblyinfo.cs のアセンブリ レベルの GUID です)。 Versionアセンブリ バージョンのメジャーおよびマイナー バージョン番号です。少し興味深いサブキーはMiscStatus. これは、ここOLEMISC に記載されている列挙の (ビット単位の) 値で構成される値に設定する必要があります。この列挙型を使用できるようにするには、(および名前空間の適切な「using」ステートメント) への参照を追加します。Microsoft.VisualStudio.OLE.Interop

彼の最後のメモは警告です。

注: これは Excel では問題なく動作するようです (私が行った非常に限られたテストで)。PowerPoint では部分的に動作しますが、Word ではうまく動作しません。おそらく、さらにいくつかのOLEMISC値がこれを改善する可能性があります。フックする必要があるメッセージがいくつかある可能性があります。おそらく、実装する必要があるインターフェースが他にもいくつかあります...非常に限られた方法でかろうじて動作するようになっただけであるという事実は、これがおそらく深刻な方法で使用したい手法ではないことを示しています.

于 2019-01-21T19:15:06.097 に答える