I'm trying to embed Excel 2013 in a WPF app. The problem is that when I call SetWindowLongPtr in the following code, Excel 2013 crashes immediately. I digged it and found that if I comment out WS.CHILD style, it works fine, but the Excel sheet becomes readonly, which is not what I want. The same code works fine with Excel 2010.
Excel.Application _excelApp;
IntPtr _wrappedApplicationHandle;
Int64 lngStyle;
Int64 lExStyle;
private void Button_Click_1(object sender, RoutedEventArgs e)
{
_excelApp = new Excel.Application()
{
Visible = true,
DisplayFormulaBar = true,
};
_wrappedApplicationHandle = new IntPtr( _excelApp.Hwnd);
lngStyle = GetWindowLongPtr(_wrappedApplicationHandle, (int)GWL.STYLE).ToInt64();
lngStyle &= ~(int)WS.CAPTION;
lngStyle &= ~(int)WS.SIZEBOX;
lngStyle |= (int)WS.MAXIMIZE;
lngStyle |= (int)WS.CHILD; //<< crashes with this line
lngStyle |= (int)WS.CLIPSIBLINGS;
lngStyle |= (int)WS.CLIPCHILDREN;
SetWindowLongPtr(new HandleRef(_excelApp, _wrappedApplicationHandle),
(int)GWL.STYLE,
new IntPtr(lngStyle));
...
}
EDIT
Some more information as I'm digging through. I tried wrapping the above code in a try/catch block to see what happens. It never reaches the catch block. Excel 2013 crashes with the infamous "Application has stopped working. Send report to MS" error. I have already turned on all Win32 / COM / C++ Exceptions in Visual Studio (through Debug menu > Exceptions dialog), but that doesn't help either. There is a Debug button in the error dialog. If I click that and open a debugger, the error msg I see is " 0xC0000005: Access violation reading location 0x0000000000000000."
I also found that commenting out the WS.CHILD line in the above code doesn't strictly make the worksheet readonly. It just blocks common keyboard/mouse input from reaching the worksheet. But some keys like the context-menu key of the keyboard still reaches there and the context menu is shown (right-clicking through the mouse doesn't work though). Similarly, I can interact with the Office Ribbon through the mouse. It appears as if only the worksheet area (the grid with the white background) is not receiving keyboard/mouse input.
EDIT 2
I just recalled that (apparently) in contrast to what Hans Passant has explained in his post below, VS2010 hosts an Excel instance in itself when you create a Excel VSTO Workbook project. Though I don't have VS2013 (Full) with me and can't confirm, I suspect VS2013 would do the same with Excel 2013 VSTO Workbook projects. Considering that VS2010 and above are all WPF applications themselves, how does that fit in the picture?
EDIT 3
That private interfaces theory suggested by #acelent (see comment below) appears to be correct. I spied into VS2010-hosted Excel instance and found that there was a new window with classname = EXCELI which is not there when we normally open Excel (normal hierarchy of windows is XLMAIN (application) > XLDESK (workspace area) > EXCEL7 (workbook)). Also that workbook is no longer available as an ActiveX object, which used to be the cases back when Office Web Components library was available (last shipped with Office 2003). So all in all, we seem to be on a dead end and I'm going to suggest #Hans's answer to my client unless someone comes up with an actual working method in the next few hours.
You'll need to give up on this, you cannot make it work reliably.
WS_CHILD cannot work by design, Windows has the rock-hard requirement that the parent window and its child belong to the same process. They pass messages between each other, the child will crash when it tries to dereference a pointer that belongs to the parent's process.
Windows does have some appcompat support for SetParent(), required because this was commonly done in Windows 3.x programs. The notion of processes with separate address spaces was entirely absent in that Windows version so it wasn't a problem back then. The odds that this still actually works properly after 20 years is proportional to how much the process behaves like a Windows 3.x app. It works okayish for a console window or a simple app like Notepad. Office 2013 apps are considerably beyond simple and 3.x. Having trouble with input is certainly a hallmark for this. You could tinker with AttachThreadInput() to try to solve it but you'll likely just run head-on into the next problem, including its nasty habit of causing deadlock when you debug.
Embedding Office apps used to be a strongly supported feature in Office, Microsoft intentionally designed them to be embeddable. The underlying technology was called OLE Linking and Embedding. This technology is however strongly deprecated. Support for it was intentionally left out of the .NET Framework. Office 2003 was the last version that still supported it well. Trouble started at 2007 and it was completely scrapped for 2010. It will not come back.
The way ahead here is the exact opposite one. Don't embed the Office app, let the Office app embed you. Writing add-ins for Office programs is strongly supported.
Related
My program uses C# and interop to create complex Excel documents. The generation process runs against an invisible background instance of Excel. One particular interop call sometimes runs incredibly slowly. Most individual interop commands take just a few milliseconds, but assigning to the Font.Bold property can sometimes take 40-60s.
The 'slow' runs of this line of code are intermittent but follow a pattern. After a slow run, all successive runs will be fast for about 7-10 minutes, after which the next call will be slow. It is like there is a 'timer' which is reset on each slow run. While the timer is counting down all interop runs smoothly. Once the timer has expired, the next assignment to Font.Bold will be slow. It will be slow no matter whether the call comes immediately after the timer has expired, or if I leave the computer idle for a couple of hours and run the code again.
Restarting my program has no impact on this invisible timer. In other words I can run my code, wait for a slow run, and then exit the process. Then if I immediately start my code again, I will get fast runs for the next 7-10 minutes. I have ensured there are no instances of Excel or other Office apps running, including hidden ones lingering in the background. The only thing which 'resets' the timer is restarting my machine. It is like the timer exists on a system level outside of Excel or my code.
This applies in Debug and Release solution configurations, running with and without the debugger attached.
There is one other crucial piece of evidence. If I manually open an instance of Excel from the Start menu (i.e. driving it using mouse and keyboard rather than interop), there are repro steps for what looks like the same problem.
Create blank workbook
In the Home ribbon click Cell Styles
Right-click a style and click Modify...
Click the Format... button
Excel completely freezes for 40-60 seconds, then finally the dialog opens and behaves as normal
The freeze in the final step follows the same 7-10 minute cooldown behaviour as when I assign to the Font.Bold property in interop. The invisible 'timer' in the background is apparently shared between the Excel dialog and the interop code. In other words a slow run in interop will be followed by 7-10 minutes of Excel not freezing. And a frozen dialog in Excel is followed by 7-10 minutes of fast interop.
I have phrased this question as one about interop since that is how I first came across the problem. It may in fact just be a general Excel problem or bug, but it was only after many fruitless days of debugging my code, trying desperate garbage collection/Marshal.ReleaseComObject nonsense etc. that I discovered the Excel GUI symptom.
What is causing this slowness and what can I do about it?
Windows version: Windows 10 Home 21H1 (19043.2006)
Excel version: version 2209 Build 16.0.15629.20152 64-bit
I have a partial answer or at least explanation to my own question.
My deduction is, Excel hangs while trying to contact an offline printer. Work around the problem by setting the Windows default printer to one which is available.
The key was finding a post (archive 1, 2) where someone describes the Excel freezing dialog symptom, and suggests changing the system default printer. My Windows default printer was set to a network-attached HP LaserJet which Windows Printers & scanners says is Online even though it's not been connected to the network or powered on in months. Changing the default printer to Microsoft Print to PDF eliminated the hangs both from interop and the live usage of Excel GUI.
This is speculation, but I imagine when the freeze happens Excel is trying to contact the printer, perhaps to determine which device fonts it supports. The Excel GUI thread (!) is ultimately blocked on a network call which times out. The 40-60 seconds is presumably the network timeout on trying to reach the printer, and the 7-10 minute 'timer' is an actual OS-wide timer which says 'if connection to a network printer fails assume it is unreachable and don't try to contact it again in this interval'.
I've tried on another machine with a different offline default printer, but I could not reproduce. Presumably the problem is only with specific printer drivers.
I'm not sure what can be done to prevent this problem in the wild when the code is running on other systems. Hopefully the problematic configuration is rare. I feel the blame could equally lie with Excel, a printer driver, or the Windows OS, so a bug fix seems unlikely.
I have developed a Microsoft Outlook Add-in for reporting suspicious emails to our IT Sec team. The Add-in basically consists of a button which is shown in the "Outlook Mail Explorer Ribbon", the "Outlook Mail Read Ribbon" and the context menu which opens up when right-clicking any email. The Add-in simply forwards any selected email to our IT Sec's mailbox for spam/phishing/...
The Add-in itself performs as expected, I only have trouble with the loading times (whenever I start Outlook, not only when first starting after installation).
I have taken a lot of information regarding Ribbon Designer VS XML from this SO answer (thanks bud!). I have decided to go for the Ribbon XML because of the ability to manipulate the context menu and the easy and clean way to design it. In addition, I created a Windows installer for installing the Add-in system-wide (see information below).
When developing this Add-in on my private PC, I had "normal" loading times and no problems with the Add-in. However, with the notebook of my company I am experiencing very high loading times. Outlook itself states that the average delay caused by the Add-in is around 2 seconds. The Add-in does not get disabled because of a GPO which places the Add-in on the "DoNotDisableAddinList" as described here.
Nevertheless, I do want to boost the performance. In the end, you can even see at the Outlook loading screen that Outlook "gets stuck" for those 2 seconds when loading the Add-in. This is not a solution for me.
What I have done so far
Basically, I tried a lot of stuff to boost the performance. First, I was having a look at this article of Microsoft which is about how to boost the performance of Office Add-ins. Unfortunately, I found none of these hints applicable for my case or I have already realized them (correct me if I am wrong):
Load VSTO Add-ins on demand: I want the buttons to be available as soon as Outlook starts, so that's not an option for me I guess
Publish Office solutions by using Windows Installer: Already done as described in this article of Microsoft
Bypass Ribbon reflection: Tried to do so but in my eyes not possible when using Ribbon XML
Perform expensive operations in a separate execution thread: Not applicable, there are no "expensive operations", simply the Add-in buttons should be loaded
What I could find out
I then tried to identify any "expensive" operation and therefore started my application in debug mode with a breakpoint at
protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
return new Ribbon();
}
After stepping over the first breakpoint (2 x F10), the Outlook loading screen shortly shows up and then Visual Studio shows up again with the next operation which is the GetCustomUI-method of my Ribbon.cs. This one loads the XML which contains the definition of my button (location, callback, image, label, ...). As you can see in the picture below, the execution time for this functions is very long (> 2000 ms). This screenshot is taken from my company notebook. On my private PC, the loading time is around 300 - 400 ms.
I then thought about slow IO for loading the XML file and hardcoded the XML content into the source code (I know, very dirty, but just for testing purposes), but no change. The function still executed for 2000 ms.
Right now, I don't know what to try next and I am a bit helpless. Maybe someone of you has any idea. When required, I can also post more parts of the source code. Any help is appreciated. Thank you in advance!
If your addin only acts in response to ribbon and context menu clicks, it needs to be on-demand - Outlook loads it the first time, then caches the Ribbon XML and the next time it is loaded only when the users clicks on your control.
Also keep in mind that you get punished for using .Net - Outlook has to load the specific version of .Net you are using before it executes anything in your addin.
I created VSTO Outlook add-in that has a button within the main ribbon of outlook and when clicked it lunches windows form. It works great to send the data from the form to the database and it composes email as well.
My problem is that users within a company that had it installed are getting slow load notification and the add-in is disabled. I tried to fix it and change all code for multi-threading but it seems not to improve the load time much. Is there any other way to make sure add-in on all user's machines is always enabled. Maybe some other way to publish other than ClickOnce.
Thanks in advance for any help.
Multithreading won't help you much - Outlook looks at your addin startup times, not the time it takes to respond to the button click.
If you are using .Net, you get punished for that - the .Net run-time has to be loaded before a single line of your addin code gets executed. Unless you switch to an unmanaged language (such as C++ or Delphi), there is nothing you can do about that.
I am developping an Excel addin in C#.
This addin contains panels with some buttons to open hovering Forms.
I have been notified that this feature doesn't work anymore with one computer in my company. It uses Excel Office 2016 to the latest version.
Here is what happens:
The grey box is what should be a Windows Form, but for some reasons it doesn't load up. The user clicks a button to open it, and it just stays grey with no controls, no events, no response of any kind.
Now, here is the code that should open the Form :
private void _Form_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
// ActiveForm() returns basically a UserForm with some methods to fit my specific needs
ActiveForm().ShowMyForm(_columnButton); // --> ClickEvent
}
public void ShowMyForm(object parent = null)
{
ActiveForm().StartPosition = FormStartPosition.CenterScreen;
if (parent != null)
ComputeLocation(parent);
IntPtr handle = new IntPtr(Excel.Hwnd);
ActiveForm().Show(new WindowWrapper(handle)); // --> Shows a grey box
}
public class WindowWrapper : IWin32Window
{
private IntPtr _hwnd;
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get { return _hwnd; }
}
}
I'm giving this code just in case, but I'm not really sure it is faulty.
The exact same code works perfectly fine on any other machine, and the problem occurs with any version of my addin.
I've checked it with several (stable) versions, and even with a beta version, the issue still occurs.
However, it appeared after the addin was reinstalled to a previous version on the computer. It isn't supposed to mess with anything external, but I believe it is important to point it out.
I'm using a msi installer generated with Wix 3.11 to install.
I have not modified the code, but here is what I have tried. I hope this isn't ridiculous, I'm kind of unexperienced with this:
- Uninstalling and reinstalling the addin,
- Repairing Office 2016 and then Uninstall/Reinstall when it wouldn't change anything,
- Updated the .NET version from 4.6 to 4.7.2 (the addin requires 4.6)
- Updated the graphic card drivers on the computer
In addition, I've tried to check logs to see if any kind of error was generated:
- My addin shows no error in the logs
- I've set up the Visual Studio project and started the addin on debug mode, with breakpoints and all --> no error of any kind
- I've checked the Windows Logs Events and found nothing related. I might have missed something since I'm not experienced to read them.
I have finally found a link that "did something" :
How to revert to an earlier version of office 2016
I reverted the Office version to 16.0.9330.2118, and the Forms started working as expected for around 30 minutes. Then I was notified that the issue had come back, even though nothing had been updated on the computer. It just "went wrong again". I updated Office to the latest version and it started working again until next morning.
As you can see, no error is generated, but swapping the Office version to a different one "does something". It looks like some kind of conflict with some Office libraries, but I have no idea what to do or how to deal with that.
Even though I've noticed a few topics that looked like my issue, they were all related to code and Forms management. I really believe this has nothing to do with code, even though I can't prove it for certain.
Can anybody help me with this? Even some thoughts on how to deal with this issue would be appreciated, since I'm really not comfortable with it.
EDIT:
So I kind of figured out what happened, but not entirely.
I did what #HansPassant told me and ran the VS debugger on my colleague's computer, step by step, and got it running again and again.
It appeared what was causing the issue was the ComputeLocation method (see the original content).
Basically ComputeLocation worked like this (I simplified it a bit):
private void ComputeLocation(object parent)
{
Control parentControl = (Control) parent;
Point location = parentControl .PointToScreen(new Point(0,0));
//Process location's coordinates here
location = parentControl.PointToClient(location);
ActiveForm().StartPosition = FormStartPosition.Manual;
ActiveForm().Location = location;
}
I finally noticed that the issue would happen when using PointToClient. The Form would change its location but its content wouldn't.
I got the expected behavior upon removing the call to PointToClient.
I'd like to point out that this code is actually faulty (as opposed to what I was saying in the original part), because ActiveForm() is a topMost Form and has no parent. Using PointToClient in this context is a mistake because its location is always expressed in screen coordinates, although this is not what caused my issue here : in this context, PointToClient always returns a location that is almost the same as the screens coordinates.
I ended up removing permanently the call to PointToClient, clearing the issue. The content of the form followed its container again.
I still have no clue why PointToClient causes this behavior.
A few days later, another colleague got the exact same issue whereas nothing had been updated on his computer. The addin went from running normally on an excel workbook to displaying grey boxes on the next one.
I don't know if I should mark this question as solved since I was able to remove the issue, but do not fully understand what causes it.
I believe I have found what caused the issue here.
The problem "spread" to 2 more computers in my company and I was able to fix them with the correction I made, even though I didn't know the real cause.
One more issue appeared over time: ToolStrips controls weren't displayed anymore in the add-in forms.
Ultimately, one of my coworkers had to update his Windows version and it totally wiped out all of the issues.
I checked, all 3 computers were running on Windows 10 Version 1709.
I found a link about this version issues, but I'm not entirely sure this is exactly what caused the faulty behaviors:
https://support.microsoft.com/en-us/help/4340917/windows-10-update-kb4340917
The other machines were quickly updated to the Windows 10 April 2018 upgrade, and everything is running fine again on every versions of the add-in.
I have a VSTO addin for Outlook 2013. The odd thing is sometimes when I do something seemingly unconnected. My button group disappears from the place it was in. Was there working perfectly for a long time. I added a ribbon group launcher, and it vanished. I then rolled back the pending changes and it still isn't there.
First, why does my ribbon group always disappear, it is set to Position: AfterOfficeId GroupMailDelete and the tab is set to TabReadMessage. This has always worked for me up until just now. I looked up the Office Id's for elements in office 2013 in the docs and they are correct (and as I said it's been fine for months).
Second, why does it not reappear when I rollback changes? I only changed that file and when I rolled back it looked like it did before I touched it.
Also it was working right until I made the change. Tested before, worked, tested again my ribbon group is gone.
I really can't stand this problem as it messes up my entire addin. Someone please offer assistance as none of the other SO answers or anything else I've found have helped.
Thanks a ton
EDIT:
Rewrote the program copying over the logic and redoing the ribbon and forms in designer. Register the event handlers was a pain as was constructing the two forms, one from EF and one using raw sql. But aside from that it works now. Why would it work when I rewrite it, but still not work when I rollback the breaking change? Not to mention that same change didn't break the copy I rewrote.
For anyone researching this in the future, try this link - which worked perfectly for me: https://msdn.microsoft.com/en-us/library/ms268871(v=vs.140).aspx
Did you check out the list of running COM add-ins right after the ribbon disappeared? Is your add-in listed in the list as an active one?
Microsoft Office applications can disable add-ins that behave unexpectedly. If an application does not load your add-in, the application might have hard disabled or soft disabled your add-in.
Hard disabling can occur when an add-in causes the application to close unexpectedly. It might also occur on your development computer if you stop the debugger while the Startup event handler in your add-in is executing.
Soft disabling can occur when an add-in produces an error that does not cause the application to unexpectedly close. For example, an application might soft disable an add-in if it throws an unhandled exception while the Startup event handler is executing.
When you re-enable a soft-disabled add-in, the application immediately attempts to load the add-in. If the problem that initially caused the application to soft disable the add-in has not been fixed, the application will soft disable the add-in again. Read more about that in the How to: Re-enable an Add-in That Has Been Disabled article.
Do you get any UI errors?
See How to: Show Add-in User Interface Errors for more information.
Finally, what ribbon XML do you use? Could you be more specific?