internal static void UnregisterMethods() { object xlCallResult; // Remove menus IntegrationHelpers.RemoveCommandMenus(); // Now take out the methods foreach (XlMethodInfo mi in registeredMethods) { if (mi.IsCommand) { XlCallImpl.TryExcelImpl(XlCallImpl.xlfSetName, out xlCallResult, mi.Name, ""); } else { // I follow the advice from X-Cell website // to get function out of Wizard XlCallImpl.TryExcelImpl(XlCallImpl.xlfRegister, out xlCallResult, pathXll, "xlAutoRemove", "J", mi.Name, IntegrationMarshalHelpers.GetExcelMissingValue(), 0); } XlCallImpl.TryExcelImpl(XlCallImpl.xlfUnregister, out xlCallResult, mi.RegisterId); } registeredMethods.Clear(); }
internal static HRESULT DllCanUnloadNow() { InitializeIntegration(); return(IntegrationHelpers.DllCanUnloadNow()); }
internal static HRESULT DllUnregisterServer() { InitializeIntegration(); return(IntegrationHelpers.DllUnregisterServer()); }
private static void LoadIntegration() { // Get the assembly and ExcelIntegration type - will be loaded from file or from packed resources via AssemblyManager.AssemblyResolve. Assembly integrationAssembly = Assembly.Load("ExcelDna.Integration"); // Check if ExcelDna.Integration was loaded from the Global Assembly Cache if (integrationAssembly.GlobalAssemblyCache) { // Prevent using the version in the GAC to avoid add-ins using the wrong version and breaking // https://github.com/Excel-DNA/ExcelDna/pull/250#issuecomment-508642133 throw new InvalidOperationException("ExcelDna.Integration was loaded from Global Assembly Cache, and that's not allowed."); } Type integrationType = integrationAssembly.GetType("ExcelDna.Integration.ExcelIntegration"); // Check the version declared in the ExcelIntegration class int integrationVersion = (int)integrationType.InvokeMember("GetExcelIntegrationVersion", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, null); if (integrationVersion != ExcelIntegrationVersion) { // This is not the version we are expecting! throw new InvalidOperationException("Invalid ExcelIntegration version detected."); } // Get the methods that need to be called from the integration assembly MethodInfo tryExcelImplMethod = typeof(XlCallImpl).GetMethod("TryExcelImpl", BindingFlags.Static | BindingFlags.Public); Type tryExcelImplDelegateType = integrationAssembly.GetType("ExcelDna.Integration.TryExcelImplDelegate"); Delegate tryExcelImplDelegate = Delegate.CreateDelegate(tryExcelImplDelegateType, tryExcelImplMethod); integrationType.InvokeMember("SetTryExcelImpl", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { tryExcelImplDelegate }); MethodInfo registerMethodsMethod = typeof(XlRegistration).GetMethod("RegisterMethods", BindingFlags.Static | BindingFlags.Public); Type registerMethodsDelegateType = integrationAssembly.GetType("ExcelDna.Integration.RegisterMethodsDelegate"); Delegate registerMethodsDelegate = Delegate.CreateDelegate(registerMethodsDelegateType, registerMethodsMethod); integrationType.InvokeMember("SetRegisterMethods", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { registerMethodsDelegate }); MethodInfo registerWithAttMethod = typeof(XlRegistration).GetMethod("RegisterMethodsWithAttributes", BindingFlags.Static | BindingFlags.Public); Type registerWithAttDelegateType = integrationAssembly.GetType("ExcelDna.Integration.RegisterMethodsWithAttributesDelegate"); Delegate registerWithAttDelegate = Delegate.CreateDelegate(registerWithAttDelegateType, registerWithAttMethod); integrationType.InvokeMember("SetRegisterMethodsWithAttributes", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { registerWithAttDelegate }); MethodInfo registerDelAttMethod = typeof(XlRegistration).GetMethod("RegisterDelegatesWithAttributes", BindingFlags.Static | BindingFlags.Public); Type registerDelAttDelegateType = integrationAssembly.GetType("ExcelDna.Integration.RegisterDelegatesWithAttributesDelegate"); Delegate registerDelAttDelegate = Delegate.CreateDelegate(registerDelAttDelegateType, registerDelAttMethod); integrationType.InvokeMember("SetRegisterDelegatesWithAttributes", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { registerDelAttDelegate }); MethodInfo registerRtdWrapperMethod = typeof(XlRegistration).GetMethod("RegisterRtdWrapper", BindingFlags.Static | BindingFlags.Public); Type registerRtdWrapperDelegateType = integrationAssembly.GetType("ExcelDna.Integration.RegisterRtdWrapperDelegate"); Delegate registerRtdWrapperDelegate = Delegate.CreateDelegate(registerRtdWrapperDelegateType, registerRtdWrapperMethod); integrationType.InvokeMember("SetRegisterRtdWrapper", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { registerRtdWrapperDelegate }); MethodInfo getResourceBytesMethod = typeof(AssemblyManager).GetMethod("GetResourceBytes", BindingFlags.Static | BindingFlags.NonPublic); Type getResourceBytesDelegateType = integrationAssembly.GetType("ExcelDna.Integration.GetResourceBytesDelegate"); Delegate getResourceBytesDelegate = Delegate.CreateDelegate(getResourceBytesDelegateType, getResourceBytesMethod); integrationType.InvokeMember("SetGetResourceBytesDelegate", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { getResourceBytesDelegate }); // set up helpers for future calls IntegrationHelpers.Bind(integrationAssembly, integrationType); IntegrationMarshalHelpers.Bind(integrationAssembly); }
public XlParameterInfo ReturnType; // Macro will have ReturnType null (as will native async functions) // THROWS: Throws a DnaMarshalException if the method cannot be turned into an XlMethodInfo // TODO: Manage errors if things go wrong XlMethodInfo(ModuleBuilder modBuilder, MethodInfo targetMethod, object target, object methodAttribute, List <object> argumentAttributes) { // Default Name, Description and Category Name = targetMethod.Name; Description = ""; Category = IntegrationHelpers.DnaLibraryGetName(); HelpTopic = ""; IsVolatile = false; IsExceptionSafe = false; IsHidden = false; IsMacroType = false; IsThreadSafe = false; IsClusterSafe = false; ExplicitRegistration = false; ShortCut = ""; // DOCUMENT: Default MenuName is the library name // but menu is only added if at least the MenuText is set. MenuName = IntegrationHelpers.DnaLibraryGetName(); MenuText = null; // Menu is only // Set default IsCommand - overridden by having an [ExcelCommand] attribute, // or by being a native async function. // (Must be done before SetAttributeInfo) IsCommand = (targetMethod.ReturnType == typeof(void)); SetAttributeInfo(methodAttribute); // We shortcut the rest of the registration if (ExplicitRegistration) { return; } FixHelpTopic(); // Return type conversion // Careful here - native async functions also return void if (targetMethod.ReturnType == typeof(void)) { ReturnType = null; } else { ReturnType = new XlParameterInfo(targetMethod.ReturnType, true, IsExceptionSafe); } ParameterInfo[] parameters = targetMethod.GetParameters(); // Parameters - meta-data and type conversion Parameters = new XlParameterInfo[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { object argAttrib = null; if (argumentAttributes != null && i < argumentAttributes.Count) { argAttrib = argumentAttributes[i]; } Parameters[i] = new XlParameterInfo(parameters[i], argAttrib); } // A native async function might still be marked as a command - check and fix. // (these have the ExcelAsyncHandle as last parameter) // (This check needs the Parameters array to be set up already.) if (IsExcelAsyncFunction) { // It really is a function, though it might return null IsCommand = false; } // Create the delegate type, wrap the targetMethod and create the delegate // CONSIDER: Currently we need a special delegate type here so that we can hook on the marshaling attributes. // Future version might do straight-forward marshaling, so we can get rid of these types (just use generic methods) // FirstArgument (if received) is not used in the delegate type created ... Type delegateType = CreateDelegateType(modBuilder); // ... but is baked into the delegate itself. Delegate xlDelegate = CreateMethodDelegate(delegateType, targetMethod, target); // Need to add a reference to prevent garbage collection of our delegate // Don't need to pin, according to // "How to: Marshal Callbacks and Delegates Using C++ Interop" // Currently this delegate is never released // TODO: Clean up properly DelegateHandle = GCHandle.Alloc(xlDelegate); FunctionPointer = Marshal.GetFunctionPointerForDelegate(xlDelegate); }
// THROWS: Throws a DnaMarshalException if the method cannot be turned into an XlMethodInfo // TODO: Manage errors if things go wrong XlMethodInfo(MethodInfo targetMethod, object target, object methodAttribute, List <object> argumentAttributes) { // Default Name, Description and Category Name = targetMethod.Name; Description = ""; Category = IntegrationHelpers.DnaLibraryGetName(); HelpTopic = ""; IsVolatile = false; IsExceptionSafe = false; IsHidden = false; IsMacroType = false; IsThreadSafe = false; IsClusterSafe = false; ExplicitRegistration = false; ShortCut = ""; // DOCUMENT: Default MenuName is the library name // but menu is only added if at least the MenuText is set. MenuName = IntegrationHelpers.DnaLibraryGetName(); MenuText = null; // Menu is only // Set default IsCommand - overridden by having an [ExcelCommand] attribute, // or by being a native async function. // (Must be done before SetAttributeInfo) IsCommand = (targetMethod.ReturnType == typeof(void)); SetAttributeInfo(methodAttribute); // We shortcut the rest of the registration if (ExplicitRegistration) { return; } FixHelpTopic(); // Return type conversion // Careful here - native async functions also return void if (targetMethod.ReturnType == typeof(void)) { ReturnType = null; } else { ReturnType = new XlParameterInfo(targetMethod.ReturnType, true, IsExceptionSafe); } ParameterInfo[] parameters = targetMethod.GetParameters(); // Parameters - meta-data and type conversion Parameters = new XlParameterInfo[parameters.Length]; for (int i = 0; i < parameters.Length; i++) { object argAttrib = null; if (argumentAttributes != null && i < argumentAttributes.Count) { argAttrib = argumentAttributes[i]; } Parameters[i] = new XlParameterInfo(parameters[i], argAttrib); } // A native async function might still be marked as a command - check and fix. // (these have the ExcelAsyncHandle as last parameter) // (This check needs the Parameters array to be set up already.) if (IsExcelAsyncFunction) { // It really is a function, though it might return null IsCommand = false; } }