2012-06-09 38 views
0

我寫了一個C#類庫,並希望在VBScript中使用它。 這裏是我的代碼:裹C#代碼的ActiveX

using System; 
using System.Collections.Generic; 
using System.Text; 
using Microsoft.PointOfService; 
using System.Runtime.InteropServices; 
using Microsoft.Win32; 
using System.Reflection; 
using System.ComponentModel; 

namespace IndigoDynamic 
{ 
    #region class implements IAsyncResult 
    [ProgId("IndigoDynamic.VirtualManager")] 
    [ClassInterface(ClassInterfaceType.AutoDispatch)] 
    [ComVisible(true)] 
    public class AsyncResult : IAsyncResult 
    { 
     object _state; 
     private bool m_completed; 
     private System.Threading.ManualResetEvent m_handle; 
     private Exception m_exception; 

     public bool IsCompleted 
     { 
      get { return m_completed; } 
      set { m_completed = value; } 
     } 

     public System.Threading.WaitHandle AsyncWaitHandle 
     { 
      get { return m_handle; } 
      set { m_handle = (System.Threading.ManualResetEvent)value; } 
     } 

     public object AsyncState 
     { 
      get 
      { 
       if (Exception != null) 
       { 
        throw Exception; 
       } 
       return _state; 
      } 
      internal set 
      { 
       _state = value; 
      } 
     } 

     public bool CompletedSynchronously { get { return IsCompleted; } } 

     internal Exception Exception 
     { 
      get { return m_exception; } 
      set { m_exception = value; } 
     } 
    } 
    #endregion 

    #region extends CashDrawer 
    [ProgId("IndigoDynamic.VirtualManager")] 
    [ClassInterface(ClassInterfaceType.AutoDispatch)] 
    [ComVisible(true)] 
    public class MyCashDrawer 
    { 
     private CashDrawer me; 
     public delegate void status_callback(int newstatus); 

     private status_callback myF; 

     public MyCashDrawer(CashDrawer param) 
     { 
      me = param; 
      me.StatusUpdateEvent += new StatusUpdateEventHandler(this.StatusUpdate); 
     } 

     [ComVisible(true)] 
     public void Claim(int timeout) { me.Claim(timeout); } 

     [ComVisible(true)] 
     public void Close() { me.Close(); } 

     [ComVisible(true)] 
     public void Open() { me.Open(); } 

     [ComVisible(true)] 
     public void OpenDrawer() { me.OpenDrawer(); } 

     [ComVisible(true)] 
     public void Release() { me.Release(); } 

     [ComVisible(true)] 
     public void Release(int timeout, int freq, int duration, int delay) 
     { 
      me.WaitForDrawerClose(timeout, freq, duration, delay); 
     } 

     [ComVisible(true)] 
     public int StatusClosed() { return CashDrawer.StatusClosed; } 

     [ComVisible(true)] 
     public int StatusOpen() { return CashDrawer.StatusOpen; } 

     [ComVisible(true)] 
     public bool Claimed() { return me.Claimed; } 

     [ComVisible(true)] 
     public bool DeviceEnabled() { return me.DeviceEnabled; } 

     [ComVisible(true)] 
     public bool DrawerOpened() { return me.DrawerOpened; } 

     [ComVisible(true)] 
     public ControlState State() { return me.State; } 

     [ComVisible(true)] 
     public void addStatusCallback(status_callback f) 
     { 
      myF = f; 
     } 

     [ComVisible(true)] 
     public void removeStatusCallback(status_callback f) 
     { 
      if (myF == f) 
       myF = null; 
     } 

     [ComVisible(true)] 
     private void StatusUpdate(object sender, StatusUpdateEventArgs arg) 
     { 
      if (myF != null) 
       myF(arg.Status); 
     } 
    } 
    #endregion 

    [ProgId("IndigoDynamic.VirtualManager")] 
    [ClassInterface(ClassInterfaceType.AutoDispatch)] 
    [ComVisible(true)] 
    class VirtualManager : ISynchronizeInvoke 
    { 
     private readonly object _sync; 

     // Constructor 
     public VirtualManager() 
     { 
      _sync = new object(); 
     } 

     #region implements methods of ISynchronizeInvoke 
     public IAsyncResult BeginInvoke(Delegate method, object[] args) { 
      AsyncResult result = new AsyncResult(); 

      System.Threading.ThreadPool.QueueUserWorkItem(delegate { 
       result.AsyncWaitHandle = new System.Threading.ManualResetEvent(false); 
       try { 
        result.AsyncState = Invoke(method, args); 
       } catch (Exception exception) { 
        result.Exception = exception; 
       } 
       result.IsCompleted = true; 
      }); 

      return result; 
     } 

     public object EndInvoke(IAsyncResult result) { 
      if (!result.IsCompleted) { 
       result.AsyncWaitHandle.WaitOne(); 
      } 

      return result.AsyncState; 
     } 


     public object Invoke(Delegate method, object[] args) { 
      lock (_sync) { 
       return method.DynamicInvoke(args); 
      } 
     } 

     public bool InvokeRequired { 
      get { return true; } 
     } 
     #endregion 

     [ComVisible(true)] 
     public MyCashDrawer getCashDrawer() 
     { 
      PosExplorer posExplorer = new PosExplorer(this); 
      DeviceInfo deviceInfo = posExplorer.GetDevice(DeviceType.CashDrawer); 
      if (deviceInfo == null) 
      { 
       //<report failure > 
       return null; 
      } 
      else 
      { 
       CashDrawer cd = posExplorer.CreateInstance(deviceInfo) as CashDrawer; 

       return new MyCashDrawer(cd); 
      } 
     } 

     [ComVisible(true)] 
     public MyCashDrawer getCashDrawer(String name) 
     { 
      PosExplorer posExplorer = new PosExplorer(this); 
      DeviceInfo deviceInfo = posExplorer.GetDevice(DeviceType.CashDrawer, name); 
      if (deviceInfo == null) 
      { 
       //<report failure > 
       return null; 
      } 
      else 
      { 
       CashDrawer cd = posExplorer.CreateInstance(deviceInfo) as CashDrawer; 
       return new MyCashDrawer(cd); 
      } 
     } 

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

      RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true); 

      RegistryKey ctrl = k.CreateSubKey("Control"); 
      ctrl.Close(); 

      RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true); 
      inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase); 
      inprocServer32.Close(); 

      k.Close(); 
     } 

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

      RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true); 

      if (k == null) 
      { 
       return; 
      } 
      k.DeleteSubKey("Control", false); 

      RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true); 
      inprocServer32.DeleteSubKey("CodeBase", false); 
      inprocServer32.Close(); 
      k.Close(); 
     } 
    } 
} 

建成後,我用RegAsm但它扔警告否類型註冊。 然後,我寫了一個示例代碼,但它說ActiveX不能創建對象。

Sub main 
    set objTest = CreateObject("IndigoDynamic.VirtualManager") 
end sub 

call main 

有人說,我要檢查的AssemblyInfo.cs,並確保我有

[assembly: ComVisible(true)] 

我當然有,但問題仍然沒有解決。 有人可以告訴我一個解決方案嗎?


我改變了我的代碼。更簡單,沒有線程,沒有界面,一切都是公開的。 但它仍然無法正常工作。 請,我真的需要幫助。

using System; 
using System.Collections.Generic; 
using System.Text; 
using Microsoft.PointOfService; 
using System.Runtime.InteropServices; 
using Microsoft.Win32; 
using System.Reflection; 
using System.ComponentModel; 

namespace IndigoDynamic 
{    
    [ProgId("IndigoDynamic.VirtualManager")] 
    [ClassInterface(ClassInterfaceType.AutoDispatch)] 
    [ComVisible(true)] 
    public class VirtualManager 
    { 
     public VirtualManager() 
     { 
     } 

     [ComVisible(true)] 
     public CashDrawer getCashDrawer() 
     { 
      PosExplorer posExplorer = new PosExplorer(); 
      DeviceInfo deviceInfo = posExplorer.GetDevice(DeviceType.CashDrawer); 
      if (deviceInfo == null) 
      { 
       //<report failure > 
       return null; 
      } 
      else 
      { 
       CashDrawer cd = posExplorer.CreateInstance(deviceInfo) as CashDrawer; 
       return cd; 
      } 
     } 

     [ComVisible(true)] 
     public CashDrawer getCashDrawer(String name) 
     { 
      PosExplorer posExplorer = new PosExplorer(); 
      DeviceInfo deviceInfo = posExplorer.GetDevice(DeviceType.CashDrawer, name); 
      if (deviceInfo == null) 
      { 
       //<report failure > 
       return null; 
      } 
      else 
      { 
       CashDrawer cd = posExplorer.CreateInstance(deviceInfo) as CashDrawer; 
       return cd; 
      } 
     } 

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

      RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true); 

      RegistryKey ctrl = k.CreateSubKey("Control"); 
      ctrl.Close(); 

      RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true); 
      inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase); 
      inprocServer32.Close(); 

      k.Close(); 
     } 

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

      RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true); 

      if (k == null) 
      { 
       return; 
      } 
      k.DeleteSubKey("Control", false); 

      RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true); 
      inprocServer32.DeleteSubKey("CodeBase", false); 
      inprocServer32.Close(); 
      k.Close(); 
     } 
    } 
} 

回答

2

不幸遇到非常遠離可行的解決方案中刪除。警告是準確的,您所做的[ComVisible]無法由COM客戶端創建。 MyCashDrawer缺少必需的默認構造函數,COM客戶端應用程序無法將參數傳遞給構造函數。 VirtualManager不是公共的,並且來自不是[ComVisible]的接口

該代碼也缺少使ActiveX組件在ActiveX主機窗口上工作的接口所需的實現,如IOleObject,IOleInPlaceObject,IOleInplaceActiveObject,IOleWindow, IViewObject等等。此外,您公開的是ActiveX對象無法處理的實現細節,COM中的線程模型與.NET中的線程模型非常不同。

您將需要一個嚴重的不同的方法。考慮從System.Windows.Forms.Control中派生可見對象,它將處理最小的ActiveX接口實現要求。而讓線程問題,不要把它留給客戶梳理出來。

+0

喜,現在我簡單地改變我的代碼一樣, – fatpipp

0

regasm警告不是問題。 也許是因爲VirtualManager類不公開。嘗試將你的課堂公開。