Microsoft.Office.Tools.Excel.ApplicationFactory.GetVstoObject causes VBA memory leak? - c#

below is a minimum sample VSTO-Project that forces the Excel VBA-Environment to show an error "Not enough memory" and causes the VBA-Project to appear twice.
Question: Is this a bug in the "GetVstoObject"-Method. How can I get around???
Steps:
In Excel 2010: Create a new workbook and hit ALT + F11 to enter the VBA-Environment
In VBA.ThisWorkworkbook: Create an empty new Sub
Sub test()
End Sub
Save the workbook as Test.xlsm and exit Excel.
Create a new Excel 2010-Add-In in Visual Studio
Replace all code in ThisAddIn.cs by the code below.
Start debugging Excel with F5
Start debugging ExcelAddIn1 with F5
Open the saved workbook Test.xlsm.
ReOpen the saved workbook again (IMPORTANT: Must do it "externally" e.g. by using the Excel jumplist in the windows taskbar)
Results:
The CTP is doubled
If you hit ALT + F11 to open VBA, you will get an "No enough memory"-Error
Thanks for any explanation/solution!
Regards,
Jörg
C# Minimum Add-In Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Excel = Microsoft.Office.Interop.Excel;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Excel;
namespace ExcelAddIn1
{
public partial class ThisAddIn
{
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
this.Application.WorkbookActivate += new Excel.AppEvents_WorkbookActivateEventHandler(Application_WorkbookActivate);
}
void Application_WorkbookActivate(Excel.Workbook Wb)
{
//This is the important line:
var activeVstoWorkbook = Globals.Factory.GetVstoObject(Wb);
}
#region VSTO generated code
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
}
#endregion
}
}

Related

Word Document.Close does not show saving option dialog

I am writting word automation functions. My app let users click on a word document file name to open it; when users click another doc, it closes the previous one first, then opens the new one.
My problem is about closing a previous doc.
I tried _Application.Quit(WdSaveOptions.wdPromptToSaveChanges) first. It shows the saving option dialog, but it doesn't return to codes, so, a new doc could open before users' response to the dialog. That is not I want.
Sendmessage can close the Word with a saving dialog, and wait users response to the dialog. This is better than the _Application.Quit.
I like Document.Close(). It close the Document, but the Word application is not closed, so it is more quick to open the next doc than the _Application.Quit and Sendmessage.
The problem with the Document.Close is that it just saves the doc with changes without showing a saving option dialog, although I pass WdSaveOptions.wdPromptToSaveChanges as a parameter in Document.Close().
Are there some bugs in my codes or the close() has bugs itself? Thanks.
using System;
using System.Windows.Forms;
using System.IO;
using Word = Microsoft.Office.Interop.Word;
using System.Threading;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Word;
namespace Test_IE_Doc
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
int FHwnd = 0;
public Word._Application oWord;
private void button1_Click(object sender, EventArgs e)
{
string fileName = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location), "1.docx");
CloseDoc();
Thread.Sleep(1000);
if (oWord == null)
oWord = new Word.Application();
oWord.Visible = true;
oWord.Documents.Open(fileName, true);
FHwnd = oWord.Documents[1].ActiveWindow.Hwnd;
oWord.WindowState = Word.WdWindowState.wdWindowStateNormal;
SetForegroundWindow(new IntPtr(FHwnd));
}
private void CloseDoc()
{
if (FHwnd != 0)
//oWord.Quit(WdSaveOptions.wdPromptToSaveChanges);
oWord.Documents[1].ActiveWindow.Close(WdSaveOptions.wdPromptToSaveChanges);
}
}
}
I use Documents.Saved to check if the document is changed, then ask user whether the user want to save it. then Document's ActiveWindow.Close() pass WdSaveOptions.wdSaveChanges for saving, pass WdSaveOptions.wdDoNotSaveChanges for not saving.

Creating an On-send prompt in Outlook with VSTO and in C#

I have a requirement to intercept the sending of a new email. All I want to do initially is ask the user "Are you sure you want to send?" and then to either proceed with the sending or cancel it depending on their response.
I found this code snippet which looks perfect for my needs but couldn't get it to work in a Win Forms test application either in VB.Net or after trying to convert it to C#. It then occurred to me that the code may only work in a VSTO Add-in (Is this correct?).
So I then used this Walkthrough to create a VSTO Add-in in C# and made sure that it worked as described, which it does (it pumps some text into the Subject and Body of a new message).
I have tried to add the first example which is in VB.Net into the working C# example but I'm a novice and don't know enough about VSTO or C# to see where I'm going wrong.
The code compiles without errors but when run, Outlook takes a long time loading the Add-in and displays a dialogue stating:
An add-in could not be found or loaded
and then:
Could not create an instance of startup object
PromptToFile_Plug_in.ThisAddIn in assembly PromptToFile Plug-in,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
Where am I going wrong?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Diagnostics;
using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
using System.Windows.Forms;
namespace PromptToFile_Plug_in
{
public partial class ThisAddIn
{
Outlook.Inspectors inspectors;
Outlook.Application myOlApp = new Outlook.Application();
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
inspectors = this.Application.Inspectors;
inspectors.NewInspector +=
new Microsoft.Office.Interop.Outlook.InspectorsEvents_NewInspectorEventHandler(Inspectors_NewInspector);
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
// Note: Outlook no longer raises this event. If you have code that
// must run when Outlook shuts down, see https://go.microsoft.com/fwlink/?LinkId=506785
}
void Inspectors_NewInspector(Microsoft.Office.Interop.Outlook.Inspector Inspector)
{
Outlook.MailItem mailItem = Inspector.CurrentItem as Outlook.MailItem;
if (mailItem != null)
{
if (mailItem.EntryID == null)
{
mailItem.Subject = "This text was added by using code";
mailItem.Body = "This text was added by using code";
}
}
}
private void Initialize_handler()
{
myOlApp = this.Application;
}
private void myOlApp_ItemSend(object Item, bool Cancel)
{
string prompt;
// prompt = "Are you sure you want to send " + Item.Subject + "?";
prompt = "Are you sure you want to send?";
MessageBox.Show(prompt, "Prompt to File", MessageBoxButtons.OKCancel);
//if (MessageBox.(prompt, Constants.vbYesNo + Constants.vbQuestion, "Sample") == Constants.vbNo)
// Cancel = true;
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
First of all, there is no need to create a new Outlook Application instance in the add-in class:
Outlook.Application myOlApp = new Outlook.Application();
Instead, use the Application property available in your add-in class.
Second, there is no need to keep the following method because it will never be called:
private void Initialize_handler()
{
myOlApp = this.Application;
}
Unlike VBA, you can't subscribe to the events just declaring the source objects with keywords. Instead, you need to subscribe to the events in the code like you did for the NewInspector event. For example, the following code can be used for handling the ItemSend event in VSTO add-ins:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
this.Application.ItemSend += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);
}
void Application_ItemSend(object Item, ref bool Cancel)
{
if (Item is Outlook.MailItem)
{
Outlook.MailItem mail = (Outlook.MailItem)Item;
// your code goes here
}
}
Finally, pay attention to the ref attribute for the Cancel parameter in the event handler signature.

Emgu CV can't play video

I can't play play video with Emgu CV
It's show error
Unable to create capture from 184.avi
Here is the code:
public partial class Form1 : Form
{
//Set the name of pop-up window
String winname = "First Window";
Timer My_Time = new Timer();
int FPS=30;
Capture _capture;
public Form1()
{
InitializeComponent();
//Frame Rate
My_Timer.Interval = 1000 / FPS;
My_Timer.Tick += new EventHandler(My_Timer_Tick);
My_Timer.Start();
_capture = new Capture("184.avi"); // Error this line
}
private void My_Timer_Tick(object sender, EventArgs e)
{
imageBox.Image = _capture.QueryFrame().ToBitmap();
}
I use windows 8 x64 and install emgucv-windows-universal-cuda 2.4.10.1940 It have no opencv_ffmpeg.dll in bin. So I install opencv-2.4.11 and copy all dll from OpenCV bin to paste in Debug in my project. I paste 184.avi to Debug too. But when I run it show error like this. How to play video with Emgu CV?
Your code works fine. I think the problem is that you have not imported the video file to Visual Studio. So try importing the video file to visual studio and also set the properties to copy always. You can see below that i have imported the A.avi file and set it's properties to copy always.
And think you can just use imageBox.Image = _capture.QueryFrame(); instead of imageBox.Image = _capture.QueryFrame().ToBitmap();because you don't need to convert to bitmap with ImageBox.
The code i used is same as yours.
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using Emgu.CV.Features2D;
using Emgu.CV.Util;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{//Set the name of pop-up window
String winname = "First Window";
Timer My_Time = new Timer();
int FPS = 30;
Capture _capture;
public Form1()
{
InitializeComponent();
//Frame Rate
My_Time.Interval = 1000 / FPS;
My_Time.Tick += new EventHandler(My_Timer_Tick);
My_Time.Start();
_capture = new Capture("A.avi"); // Error this line
}
private void My_Timer_Tick(object sender, EventArgs e)
{
imageBox.Image = _capture.QueryFrame();
}
}
}
You can just provide full path instead of just the file name.
You do not have the video file in the same folder as your program exe.
If you place video file just next to your program exe, it should also work.

Visual Studio 2010 C# "already defined a member with same parameter types error."

im having a problem in visual studio it keeps saying i have defined a member with same parameter types. Im new to C# programming and i dont really know what to do. These are the errors that are occurring:
Error 1 Type 'Secret.AddPage' already defines a member called
'AddPage' with the same parameter types
Error 2 Type 'Secret.AddPage' already defines a member called
'PhoneApplicationPage_Loaded' with the same parameter types
Here is the code i have written so far any help is greatly appreciated.
enter code here
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Device.Location;
namespace secret
{
public partial class AddPage : PhoneApplicationPage
{
private string location = "";
public AddPage()
{
InitializeComponent();
GeoCoordinateWatcher myWatcher = new GeoCoordinateWatcher();
var myPosition = myWatcher.Position;
// Eftersom koden körs i emulatorn kan den inte få tillgång till riktiga GPS-värden
// Därför hårdkodas koordinaterna till slottet i Gamla stan så att MSR MAPS Web Services
//kan testas.
double latitude = 40.717;
double longitude = -74;
if (!myPosition.Location.IsUnknown)
{
latitude = myPosition.Location.Latitude;
longitude = myPosition.Location.Longitude;
}
myTerraService.TerraServiceSoapClient client = new myTerraService.TerraServiceSoapClient();
client.ConvertLonLatPtToNearestPlaceCompleted += new EventHandler<myTerraService.ConvertLonLatPtToNearestPlaceCompletedEventArgs>(client_ConvertLonLatPtToNearestPlaceCompleted);
client.ConvertLonLatPtToNearestPlaceAsync(new myTerraService.LonLatPt { Lat = latitude, Lon = longitude });
}
void client_ConvertLonLatPtToNearestPlaceCompleted(object sender, myTerraService.ConvertLonLatPtToNearestPlaceCompletedEventArgs e)
{
location = e.Result;
//throw new NotImplementedException();
}
private void AppBar_Cancel_Click(object sender, EventArgs e)
{
navigateBack();
}
private void AppBar_Save_Click(object sender, EventArgs e)
{ // spara en ny anteckning
if (location.Trim().Length == 0)
{
location = "Okänd";
}
navigateBack();
}
private void navigateBack()
{
NavigationService.Navigate(new Uri("/secret;component/NotesMainPage.xaml", UriKind.Relative));
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
editTextBox.Focus();
}
}
}
You are creating a partial class, so you probably have these members defined in another source file for your partial class.
You may look at the solution explorer, find that source file and either remove it from there or you may remove these members from your current partial class.
You may see: Partial Classes and Methods (C# Programming Guide)
To search for the other source file containing the partial class, right click on the Class Name AddPage and select Go to Definition. You will see multiple results in Find Symbol result window in visual studio.
Check for another partial class in which you've already defined the AddPage() constructor or PhoneApplicationPage_Loaded() methods. You can achieve this by Ctrl+F and searching the solution for the method signatures:
public AddPage()
and
PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
I had something very similar recently, and it turned out that when importing existing code files I had imported the obj directory itself!
This directory contained, for example, the auto-generated (and automatically imported) MainWindow.g.i.cs file. So I was effectively including the same partial class definition twice, hence the "already defined" errors.
How this help someone else!
i had a project where i opened the main program.cs in notepad++, made some edits and did a "save as" to make a copy of the file in the same folder. i later opened the same project in visual studio and got this same error when trying to compile. i just had to exclude the files i created from making a copy from the project by right clicking on the problem file and selecting "exclude from project". did a build and viola! the copy was still in the folder just not being included in the build.
In my case the reason of this error was finally as simple as this. I added a new DB table to my EDMX in my DB project. I accidentally ticked the box for generation of class with methods (but these were already generated in the project). The EDMX file after this contained two similarly named classes AB.Context.tt and AB.xxx.Context.tt and both contained the same methods. As the classes were partial the mentioned error arose.
The solution was to remove accidentally and freshly added secondary AB.xxx.Contex.tt file and rebuild the project.

Local Data Cache Sync does not save client changes to sdf file

I created a new c# project and follwed the steps from this tutorial to create a LocalDataCache:
http://www.codeproject.com/KB/database/AdoSyncServicesArticalPKg.aspx?fid=1526739&df=90&mpp=25&noise=3&sort=Position&view=Quick&select=2794305&fr=1#xx0xx
I next added the following code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TestLocalSync
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the table. You can move, or remove it, as needed.
this.databaseTableAdapter.Fill(this.testDataSet.myTable);
}
private void Sync_Click(object sender, EventArgs e)
{
dataGridView1.EndEdit();
// Call SyncAgent.Synchronize() to initiate the synchronization process.
// Synchronization only updates the local database, not your project’s data source.
LocalDataCache1SyncAgent syncAgent = new LocalDataCache1SyncAgent();
syncAgent.testTable.SyncDirection = Microsoft.Synchronization.Data.SyncDirection.Bidirectional;
Microsoft.Synchronization.Data.SyncStatistics syncStats = syncAgent.Synchronize();
MessageBox.Show("Changes downloaded: " +
syncStats.TotalChangesDownloaded.ToString() +
Environment.NewLine +
"Changes uploaded: " + syncStats.TotalChangesUploaded.ToString());
// TODO: Reload your project data source from the local database (for example, call the TableAdapter.Fill method).
databaseTableAdapter.Fill(testDataSet.myTable);
testDataSet.Merge(databaseTableAdapter.GetData());
databaseTableAdapter.Update(testDataSet);
}
private void Refresh_Click(object sender, EventArgs e)
{
databaseTableAdapter.Fill(testDataSet.myTable);
}
}
}
I make some changes to the database on the server and perform the sync and it appears update the client datagrid. When I re-load the application, the client (sdf database) is the same before the sync took place and no changes have been stored.
Now I am not sure what I am missing? Must be something simple! Any advice is greatfully accepted.
Thank you
This is solved now.
The problem is that the database.sdf is always copied to the data output directory and would overwrite the database I was working on (manually making changes to test the merge!).
This can be changed by clicking on the sdf file in visual studio and in properties change the value for "Copy to Output Directory" to "Do Not Copy". Then manage the connection string outside of the data directory. The default is Copy If newer which caused the problems!

Categories