私はBloombergAPI(= BDP( "MSエクイティ"、 "ask")のような単純な呼び出しを使用します)に優れています。Bloomberg APIを使用するExcelファイルを(相互運用機能を介して)開くC#アプリケーションもあります。相互運用機能を介してExcelをロードすると、アドインがロードされないことをここで読みました。そこで提案されているコードを使ってみました。ただし、これはXLLファイルとXLAMファイルでのみ機能するようであり、ブルームバーグもロードされないDLLファイルを使用しているようです。これらすべてのアドインを相互運用機能を介してロードする方法はありますか?
4 に答える
手動でExcelを起動すると、アドインが正しく読み込まれると思います。
その場合は、呼び出してからメソッドをProcess p = Process.Start("excel.exe");
使用して相互運用オブジェクトを取得することにより、BBアドインがロードされたExcel相互運用オブジェクトを取得できます。AccessibleObjectFromWindow
これを行う方法の例は、ここにあります。
クイックウォークスルー
BloombergアドインがロードされExcel.Interop.Application
たインスタンスを取得するために実行した手順を示すことにしました。たぶん誰かがこれを見てそれが役に立つと思うか、もっとエレガントな解決策を得るために私が何かを逃した場所を知っています。
ブルームバーグ端末がクライアントにインストールされており、Excelから参照データと履歴データ(BDPおよびBDH)を要求できると仮定します。そうでなければ、これはおそらくあなたのためではありません...
最も簡単な方法は機能しません
var excel = new Microsoft.Office.Interop.Excel.Application();
excel.Workbooks.Open(filePath);
excel.Run("RefreshAllStaticData");
Run()
をスローしCOMException
ます:
マクロ'RefreshAllStaticData'を実行できません。このワークブックでマクロが使用できないか、すべてのマクロが無効になっている可能性があります。
アドインを手動でロードしても機能しません
var excel = new Microsoft.Office.Interop.Excel.Application();
var addIn = ex.AddIns.Add(filename);
addIn.Installed = true;
Console.WriteLine(addIn.IsOpen);
false
しかし、WindowsタスクバーをクリックしてExcelを起動すると、アドインが正常に読み込まれています...そこで、実行可能ファイル「excel.exe」を起動してExcelを起動しようとしました。
Process.Start( "excel.exe")の使用は機能します!!
クラスを使用してExcelを開始System.Diagnostics.Process
すると、ブルームバーグアドインが読み込まれます。(私は見ることができますBloomberg-RibbonTab
。)
今必要なのは、そのExcelプロセスのInterop-Objectだけです。上記の例を使用して取得できます
それの私の実装
//From http://blogs.officezealot.com/whitechapel/archive/2005/04/10/4514.aspx
public class ExcelInteropService
{
private const string EXCEL_CLASS_NAME = "EXCEL7";
private const uint DW_OBJECTID = 0xFFFFFFF0;
private static Guid rrid = new Guid("{00020400-0000-0000-C000-000000000046}");
public delegate bool EnumChildCallback(int hwnd, ref int lParam);
[DllImport("Oleacc.dll")]
public static extern int AccessibleObjectFromWindow(int hwnd, uint dwObjectID, byte[] riid, ref Microsoft.Office.Interop.Excel.Window ptr);
[DllImport("User32.dll")]
public static extern bool EnumChildWindows(int hWndParent, EnumChildCallback lpEnumFunc, ref int lParam);
[DllImport("User32.dll")]
public static extern int GetClassName(int hWnd, StringBuilder lpClassName, int nMaxCount);
public static Microsoft.Office.Interop.Excel.Application GetExcelInterop(int? processId = null)
{
var p = processId.HasValue ? Process.GetProcessById(processId.Value) : Process.Start("excel.exe");
try
{
return new ExcelInteropService().SearchExcelInterop(p);
}
catch (Exception)
{
Debug.Assert(p != null, "p != null");
return GetExcelInterop(p.Id);
}
}
private bool EnumChildFunc(int hwndChild, ref int lParam)
{
var buf = new StringBuilder(128);
GetClassName(hwndChild, buf, 128);
if (buf.ToString() == EXCEL_CLASS_NAME) { lParam = hwndChild; return false; }
return true;
}
private Microsoft.Office.Interop.Excel.Application SearchExcelInterop(Process p)
{
Microsoft.Office.Interop.Excel.Window ptr = null;
int hwnd = 0;
int hWndParent = (int)p.MainWindowHandle;
if (hWndParent == 0) throw new ExcelMainWindowNotFoundException();
EnumChildWindows(hWndParent, EnumChildFunc, ref hwnd);
if (hwnd == 0) throw new ExcelChildWindowNotFoundException();
int hr = AccessibleObjectFromWindow(hwnd, DW_OBJECTID, rrid.ToByteArray(), ref ptr);
if (hr < 0) throw new AccessibleObjectNotFoundException();
return ptr.Application;
}
}
これで、次のコード行を使用して、Excel.Interop.Application
bloombergアドインがロードされたインスタンスを取得できます。
var excel = ExcelInteropService.GetExcelInterop();
excel.Workbooks.Open(filename);
excel.Run("RefreshAllStaticData");
// works "like a charm"
これで私がこれで無駄にした時間を誰かが節約できることを願っています。誰かがよりエレガントな解決策を持っていて、それを共有したいのであれば、それは大いにありがたいです。
この質問が出されてからしばらく経ちました。それでも、同じ問題に遭遇したときの経験を共有したいと思います。簡単な解決策は、https: //blogs.msdn.microsoft.com/accelerating_things/2010/09/16/loading-excel-add-ins-at-runtime/で提案されているように、最初に.Installedをfalseに設定してから続行することです。真に:
this._application = new Application
{
EnableEvents = true,
Visible = true
};
//Load Bloomberg Add-In
for (var i = 1; i <= this._application.AddIns.Count; i++)
{
var currentAddIn = this._application.AddIns.Item[i];
if (currentAddIn.Name != "BloombergUI.xla") continue;
currentAddIn.Installed = false;
currentAddIn.Installed = true;
}
NetOfficeを使用して同様の結果を得ることができました。この特定の関数は、Excelプロセスの最後に開始されたインスタンスを取得するか、存在する場合は新しいインスタンスを作成します。そこから、新しいワークブックを自由に開いたり作成したりできます。
netofficeとこのアプローチを使用することの良い点は、バージョン固有の相互運用機能DLLに依存せず、NetOfficeオブジェクトを破棄すると、すべてのExcelCOMオブジェクトが適切にクリーンアップされることです。
using Xl = NetOffice.ExcelApi;
private static Xl.Application GetOrStartExcel(bool started = false)
{
Xl.Application application = null;
try
{
object nativeProxy = System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
application = new Xl.Application(null, nativeProxy);
return application;
}
catch (Exception ex)
{
if (!started) Process.Start("excel.exe");
Thread.Sleep((int) TimeSpan.FromSeconds(1).TotalMilliseconds);
return GetOrStartExcel(true);
}
}
使用法:
using (var excel = GetOrStartExcel())
{
//Do work with excel object
}
DLLをExcelアドインにロードする場合は、RegAsmを使用してこのDLLファイルを登録する必要があります。そして、HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\Excel\AddIns
それが正常に登録されているかどうかを確認します。