Как загрузить надстройку Excel с помощью Interop
У меня есть надстройка, которую я хочу вызвать через Excel взаимодействия из приложения C# winforms.
Я не могу загрузить надстройку и т. Д., Если не удаляю и не устанавливаю ее каждый раз (очевидно, это связано с тем, что Excel не загружает надстройки при использовании interop - btw, не может заставить их пример работать в C#). К сожалению, это медленно и раздражает пользователя, поэтому мне нужно упростить его.
Я хочу иметь один экземпляр Excel, но загрузить уже установленную надстройку, не вызывая эту проблему установки / переустановки.
Я искал и искал, но все, что я нахожу в Google, дает решение для установки / переустановки. Есть ли другой путь? Надстройка установлена, я просто хочу, чтобы Excel загрузил ее.
Это то, что я делаю в данный момент (по совету Google):
// loop over the add-ins and if you find it uninstall it.
foreach (AddIn addIn in excel.AddIns)
if (addIn.Name.Contains("My Addin"))
addin.Installed = false;
// install the addin
var addin = excel.AddIns.Add("my_addin.xll", false);
addin.Installed = true;
3 ответа
Через некоторое время я нашел ответ, спрятанный в странных местах в справке MS: и этот пост в блоге.
Это не вся информация, которая вам нужна. На что следует обратить внимание: у вас должна быть открыта хотя бы одна рабочая книга или все остальное в Excel. Вот некоторый кодекс грубостина, чтобы начать:
var excel = new Application();
var workbook = excel.workbooks.Add(Type.Missing);
excel.RegisterXLL(pathToXll);
excel.ShowExcel();
Если вы хотите, вы можете закрыть временную рабочую книгу (если вы запустили несколько макросов и т. Д.) И не забудьте привести в порядок все множество обращений к Marshal.ReleaseComObject!
Кажется, вы должны получить правильный процесс Excel для работы. Используйте этот класс, чтобы открыть документ Excel:
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 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 Application GetExcelInterop(int? processId = null)
{
var p = processId.HasValue ? Process.GetProcessById(processId.Value) : Process.Start("excel.exe");
try
{
Thread.Sleep(5000);
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 Application SearchExcelInterop(Process p)
{
Window ptr = null;
int hwnd = 0;
int hWndParent = (int)p.MainWindowHandle;
if (hWndParent == 0) throw new Exception();
EnumChildWindows(hWndParent, EnumChildFunc, ref hwnd);
if (hwnd == 0) throw new Exception();
int hr = AccessibleObjectFromWindow(hwnd, DW_OBJECTID, rrid.ToByteArray(), ref ptr);
if (hr < 0) throw new Exception();
return ptr.Application;
}
}
Используйте класс в вашем приложении следующим образом:
static void Main(string[] args)
{
Microsoft.Office.Interop.Excel.Application oExcel = ExcelInteropService.GetExcelInterop();
foreach (AddIn addIn in oExcel.AddIns)
{
addIn.Installed = true;
}
}
У меня была аналогичная проблема, и ни одно из вышеперечисленных решений не сработало для меня. Итак, мне наконец пришла в голову идея просто открыть файл «.xla» как книгу:
//I first get the path to file, in my case it was in the same dir as the .exe
var XLA_NAME = Path.Combine(Directory.GetCurrentDirectory(), ".xla");
Excel.Application xlRep = new Excel.Application();
xlRep.visible = true;
xlRep.Workbooks.Open("XLA_NAME");