我有一個Excel加載項與一個類模塊。我想在C#中實例化類模塊並調用其中的方法。我怎麼做?如何從C#中訪問Excel VBA中的類模塊?
回答
如果你確實需要的情況下訪問類,你可以做到以下幾點:
生成一個COM接口,你想從你的VBA類暴露一個類型庫(例如IMyComInterface)
添加和借鑑e添加到VBA項目中的此類型庫
實現VBA類模塊中的接口 - 例如, MyVbaClass(請使用implements關鍵字):
Option Explicit Implements IMyComInterface Private Sub IMyComInterface_SomeMethod(...) ... End Sub ...
參考同類型庫在C#項目
創建與接受的VBA接口實例的引用的方法的標記有ComVisible特性的C#類。喜歡的東西:
public class MyVbaLoader { public IMyComInterface MyComInterface { get { return myComInterface; } set { myComInterface = value; } } }
寫VBA標準模塊中的「工廠」的方法,即採用一個對象作爲ByRef參數。該對象應該假定作爲參數傳遞的對象具有「MyComInterface」屬性,並且應該將此屬性設置爲VBA類MyClass的新實例。
Public Sub MyFactoryMethod(MyVbaLoader As Object) Dim objClass As MyVbaClass Set objClass = New MyVbaClass ... any initialization of objClass here ... ' Pass a reference to the VBA class to the C# object MyVbaLoader MyVbaLoader.MyComInterface = objClass End Sub
從您的C#代碼調用工廠方法。假設你已經打開工作簿,並在你的VBA代碼有refence「工作簿」,代碼看起來類似:
MyVbaLoader loader = new MyVbaLoader(); workbook.Application.Run("MyModule.MyFactoryMethod", loader, Type.Missing, ... , Type.Missing); // we now have a reference to the VBA class module in loader.MyComInterface // ...
正如你可以看到,這是相當複雜的。如果沒有更多細節來解決問題,那麼很難說這種複雜性是否合理,或者是否有更簡單的解決方案。
如果上述不明確,讓我知道,我會盡力澄清。
基本上,你不能從使用Application.Run從你的C#代碼調用的VBA宏中返回一個值,所以你必須求助於通過具有可以從VBA調用的方法或屬性的值傳遞一個對象到設置實例。
很好的答案,但實際上你可以從VBA宏中返回一個值 - 請參閱我的答案瞭解詳細信息。這將避免你的其他方案中唯一難看的解決方案。 – 2009-11-14 09:38:03
注意:必須將VBA類標記爲「PublicNotCreatable」,否則您將收到與HRESULT 0x800A0062相關的異常。 – robodude666 2016-08-05 23:39:30
VBA類模塊只有兩種實例化模式:private和public-not-creatable。所以,你甚至不能在另一個VB(A)項目中實例化它們,更不用說C#了。
但是,沒有什麼能阻止你擁有一個作爲類工廠的標準模塊。因此,如果您的班級模塊是Foo
,那麼您可以在名爲NewFoo
的標準模塊中使用一種方法,爲您實例化新的Foo
並將其返回給調用者。顯然,Foo
對象必須是公共不可創建的。
[你NewFoo
方法可以帶參數,所以你可以模擬參數的構造函數,這是不可用VBA中]
編輯:關於如何調用VBA函數(標準模塊中)從細節C#並使用Application.Run
獲取返回值。
private static object RunMacro(Excel.Application excelApp, string macroName, object[] parameters)
{
Type applicationType = excelApp.GetType();
ArrayList arguments = new ArrayList();
arguments.Add(macroName);
if (parameters != null)
arguments.AddRange(parameters);
try
{
return applicationType.InvokeMember("Run", BindingFlags.Default | BindingFlags.InvokeMethod, null, excelApp, arguments.ToArray());
}
catch (TargetInvocationException ex)
{
COMException comException = ex.InnerException as COMException;
if (comException != null)
{
// These errors are raised by Excel if the macro does not exist
if ( (comException.ErrorCode == -2146827284)
|| (comException.ErrorCode == 1004))
throw new ApplicationException(string.Format("The macro '{0}' does not exist.", macroName), ex);
}
throw ex;
}
}
請注意,您可以省略所有的try ... catch東西 - 所有它做的是處理特定錯誤的宏不存在,提高在這種情況下一個更有意義的異常。
該函數返回的object
可以轉換爲您需要的任何類型。例如:
object o = RunMacro(excelApp, "MyModule.MyFunc", new object[] { "param1", 2 });
if (o is string)
{
string s = (string) o;
Console.WriteLine(s);
}
假設函數實際上返回您的VBA定義的類對象的實例,那麼你可以調用對象的方法以同樣的方式,再次使用InvokeMember
:
object o = RunMacro(excelApp, "MyModule.MyFunc", new object[] { "param1", 2 });
// assume o is an instance of your class, and that it has a method called Test that takes no arguments
o.GetType().InvokeMember("Run", BindingFlags.Default | BindingFlags.InvokeMethod, null, o, new string[] {"Test"});
如果你正在做很多這些調用,那麼顯然你可以通過創建包裝器方法來爲你打電話來隱藏醜陋的細節。
請注意,我已鍵入極本從內存,所以我完全相信那裏是語法,邏輯,甚至可能事實錯誤:-)
但是您仍然沒有生成運行時可調用包裝器(RCW)的類型庫 – Joe 2009-11-13 23:41:29
正確,但您可以直接使用InvokeMember調用該類的方法。不漂亮或不愉快,但仍然可能。如果實際上只有一個成員想打電話,那麼比你的(坦率地說優秀的)答案要求的所有連接要容易得多。 – 2009-11-14 09:09:42
+1,我不知道你可以從Application.Run調用VBA函數並返回結果。我會重做我的答案以利用這一點。這給OP留下了兩個解決方案 - 從我的答案的VBA代碼中的類型庫實現接口,或者在響應中使用反射訪問VBA類成員。 – Joe 2009-11-14 10:58:01
- 1. VBA EXCEL:從模塊
- 2. 訪問使用Excel中的VBA模塊的查詢出錯
- 3. 如何從Excel VBA中的模塊調用thisWorkbook中的方法?
- 4. 如何從模塊訪問類變量?
- 5. 如何從子模塊訪問類?
- 6. Excel無法在vba訪問模塊中關閉
- 7. 訪問VBA在類模塊中收集項目
- 8. 如何訪問C#中的Excel數據
- 9. 如何在模塊導軌中訪問我的模型類?
- 10. 如何調用模塊中的ThisWorkbook在Excel VBA中
- 11. 從libgdx的核心模塊類訪問Android模塊類
- 12. 在模塊中創建的訪問類
- 13. 如何訪問joomla中的模塊
- 14. 如何從Android的庫類訪問應用程序模塊類?
- 15. 從C++訪問fortran模塊的變量
- 16. 從oustide模塊訪問的模塊
- 17. 從Excel/VBA訪問Enovia的Python界面?
- 18. 如何訪問包含的ruby模塊中的類變量?
- 19. Excel VBA將數據寫入類模塊中的字典
- 20. Flex中的訪問模塊
- 21. 從CSS模塊訪問全局類
- 22. 從其他模塊訪問類
- 23. 如何從其他模塊訪問模塊的實例變量?
- 24. 如何從VBA訪問SQLite?
- 25. 如何訪問Objective-C中id類型塊內的變量?
- 26. Python:如何從模塊訪問類的屬性
- 27. SQL訪問VBA的Excel
- 28. 如何訪問從Python中的調用模塊調用模塊名稱空間?
- 29. 如何訪問Excel中的excel文件#
- 30. 使用C訪問特定的VBA代碼模塊
喬爾在你需要他的時候在哪裏。 – 2009-11-14 00:16:13
感謝大家的出色答案。 – 2009-11-14 15:11:38