OnEnterBreakMode does not fire - visual-studio-2012

Running VS 2012. I created an add-in. I want to handle the OnEnterBreakMode event. The Exec method is called. I tried returning handled = true/false. The handler is never invoked. I tried a few variations of DTE and DTE2. I go to the Tools menu > click "MyAddIn1" and the Exec method is called. I verified the event is bound. I do not know how the life cycle of an add-in works.
StartEvents is not an override and it's not connected to anything. I find that strange...
public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
handled = false;
if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if(commandName == "MyAddin1.Connect.MyAddin1")
{
//handled = true;
// Place the following code in the Exec method of the add-in:
EnvDTE.DebuggerEvents debugEvents = _applicationObject.Events.DebuggerEvents;
debugEvents.OnEnterBreakMode += new _dispDebuggerEvents_OnEnterBreakModeEventHandler(Connect.BreakHandler);
return;
}
}
}
private DTE _applicationObject;
private AddIn _addInInstance;
// Place the following Event handler code in the add-in:
// Needed to activate event handlers in Connect.Exec.
public static void StartEvents(DTE dte)
{
Console.WriteLine("Events are attached.");
}
// OnEnterBreakMode Event.
public static void BreakHandler(dbgEventReason reason, ref dbgExecutionAction execAction)
{
Console.WriteLine("Debugger enters break mode. " + "Reason: " + reason.ToString());
}

If you create a local variable for an event, and subscribe to it, then the variable will be freed by GC after scope is left, and your event handler won't fire.
If you make debugEvents a member variable then it should work fine.

Related

C++ CLI Invoke issues

I have a MainForm class (as you'd expect, it is a form) that has a text box on it. I also have another class called 'Application_Server' That does a load of other stuff (not just form-background related, quite a lot of network based stuff etc.).
The Application_Server class runs in it's own thread, but needs to be able to update the controls on the form, for this question, we will stick with just the textbox.
The problem is that even though I am executing the command to set the text of the textBox control via 'Invoke' I am still getting the following exception during runtime:
Additional information: Cross-thread operation not valid: Control
'DebugTextBox' accessed from a thread other than the thread it was
created on.
What could be causing this? I am definitely invoking a delegate within MainForm.
Here are the relevant code segments (cut down for readability):
MainForm.h:
public ref class MainForm : public System::Windows::Forms::Form {
delegate void del_updateDebugText(String^ msg);
del_updateDebugText^ updateDebugText = gcnew del_updateDebugText(this, &MainForm::postDebugMessage);
private: void postDebugMessage(String^ message);
};
MainForm.cpp:
void EagleEye_Server::MainForm::postDebugMessage(String^ message)
{
Monitor::Enter(DebugTextBox);
if (this->DebugTextBox->InvokeRequired)
{
this->Invoke(updateDebugText, gcnew array<Object^> { message });
}
else
{
this->DebugTextBox->AppendText(message);
}
Monitor::Exit(DebugTextBox);
}
And finally, the code calling it:
void ServerAppManager::postDebugMessage(System::String^ message)
{
mainFormHandle->updateDebugText(message);
}
void ServerAppManager::applicationStep()
{
postDebugMessage("Starting\n");
// This is Run in seperate thread in MainForm.cpp
while (s_appState == ApplicationState::RUN)
{
postDebugMessage("Testing\n");
}
}
Thanks!
From background worker called bwSearch we do the call as following from the DoWork event handler:
private: System::Void bwSearch_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
//... logic
UpdateTxtOutput("Some message");
//... more logic
}
I have a RitchTextBox called txtOutput, also the windows form control containing this code is called frmMain, the UpdateTxtOutput is defined in three parts as follows:
delegate void UpdateTxtOutputDelegate(String^ text);
void UpdateTxtOutput(String^ text)
{
UpdateTxtOutputDelegate^ action = gcnew UpdateTxtOutputDelegate(this, &frmMain::Worker);
this->BeginInvoke(action, text);
}
void Worker(String^ text)
{
txtOutput->AppendText("\t" + text + "\n");
}
I managed to get it working by simplifying the method within the 'MainForm' class to:
void EagleEye_Server::MainForm::postDebugMessage(String^ message)
{
Monitor::Enter(DebugTextBox);
DebugTextBox->AppendText(message);
Monitor::Exit(DebugTextBox);
}
And then moving the 'Invoke' call to the method calling the delegate, not pretty but it works for now. I think the issue may have been caused by the form getting stuck inside an Invoke loop. I say this as I noticed that the form would lock up and stop responding after it hit the recursive Invoke statement.

how to use a separate STA thread to call clipboard from timer in console application?

I am struggling with using Clipboard from a console application. The error handler would return the following error.
"Current thread must be set to single thread apartment (STA) mode before OLE calls can be made"
I set the STA attribute to the main function and that worked well when calling from main. However, I need to cyclically call that function and in this case I get back that error.
I'm trying to figure out how to use an own thread in my funtion. Now, it just works once but in the 2nd call from my timer, I am not able to reach the area of the code after where I created the thread
public string getRawData()
{
string sChatRawTxt = string.Empty;
try
{
// copy data to clipboard using an Autoit script
Process.Start("copyChatToClipboard.au3");
System.Threading.Thread.Sleep(500);
Thread staThread = new Thread(x =>
{
if (Clipboard.ContainsText())
{
sChatRawTxt = Clipboard.GetText();
Clipboard.Clear();
}
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return sChatRawTxt;
}
This is the timer from where my function is called. If I set a breakpoint to separateComments, it only works one time, then I am no longer able to reach that position. Do I have to somehow close the thread from before?
public void OnTimedEvent_scannerCyclic(object source, ElapsedEventArgs e)
{
string sRawTxt = getRawData();
// then separate/ remove the useless data
string sComments = SeparateComments(sRawTxt);
}
[STAThread]
public static void Main(string[] args)
{
stdTimer = new System.Timers.Timer(1000);
stdTimer.Elapsed += new ElapsedEventHandler(this.OnTimedEvent_scannerCyclic);
stdTimer.Enabled = true;
while (true)
{
// main program
//System.Threading.Thread.Sleep(1000);
}
}
thanks a lot for help
So the only solution i figured was to use my own timer that i implemented in the main as below
TimeSpan deltaT = TimeSpan.FromMilliseconds(1000);
DateTime timeLastCall = DateTime.Now;
while (true)
{
// main program
DateTime currentTime = DateTime.Now;
if(currentTime - timeLastCall > deltaT)
{
Scanner.mainCyclicCall();
timeLastCall = currentTime;
}
System.Threading.Thread.Sleep(100);
}
I dont have a lot of c# experience, it is actually my first little project. I dont know if there is a better way to cyclically access Clipboard in a console application. Also using a dispatcher timer did not work out, I read console apps dont have a dispather.

How can I execute code from the Release / Release All buttons in the Release AR Documents screen

I've got a customization to the Invoice & Memo screen where I execute some custom code (web service calls) when the Release action is activated. This works fine - I knew how to replace the PXAction code and proceeded from there. Now I want to use the Release AR Documents processing screen to do the same thing, but I'm having trouble understanding where / what to override, or where to place my code.
I see the ARDocumentRelease graph constructor with the SetProcessDelegate in the source code, but I'm not sure how to proceed - whether this is where I need to be looking or not. I need to execute my code for each line being released, using the RefNbr in my code.
Since it's an static method, you can't override it. Also, you can't do like it's done in the T300, because you are in processing graph and you can't override the release button with your own. I was able to achieve it by passing callback for each AR document that have been processed.
You can call the Initialize method of the ARDocumentRelease graph to override the logic like you said. After you just have to call ReleaseDoc that uses a callback parameter instead of using the default one.
Here's the code that I came with:
public class ARDocumentRelease_Extension : PXGraphExtension<ARDocumentRelease>
{
public override void Initialize()
{
ARSetup setup = Base.arsetup.Current;
Base.ARDocumentList.SetProcessDelegate(
delegate (List<BalancedARDocument> list)
{
List<ARRegister> newlist = new List<ARRegister>(list.Count);
foreach (BalancedARDocument doc in list)
{
newlist.Add(doc);
}
AddAdditionalLogicToRelease(newlist);
}
);
Base.ARDocumentList.SetProcessCaption("Release");
Base.ARDocumentList.SetProcessAllCaption("Release All");
}
public delegate void PostPorcessing(ARRegister ardoc, bool isAborted);
private void AddAdditionalLogicToRelease(List<ARRegister> newlist)
{
ARDocumentRelease.ReleaseDoc(newlist, true, null, delegate(ARRegister ardoc, bool isAborted) {
//Add your logic to handle each document
//Test to check if it was not aborted
});
}
}
Please note that you must always call static methods from within long running process and create necessary objects there.
Processing delegate logic is implemented as long running process which creates worker thread to execute the processing logic.
You have AddAdditionalLogicToRelease() method which requires object instance in order to call and will fail during thread context switches and hence the issue. So, you must have create object instance inside the thread context and then call instance method.
In general, method that gets called from long running processes are declared static and required objects/graphs are created inside this static method to do some work. See below example how to properly override ARDocumentRelease graph for this purpose:
public class ARDocumentRelease_Extension : PXGraphExtension<ARDocumentRelease>
{
public override void Initialize()
{
Base.ARDocumentList.SetProcessDelegate(
delegate (List<BalancedARDocument> list)
{
List<ARRegister> newlist = new List<ARRegister>(list.Count);
foreach (BalancedARDocument doc in list)
{
newlist.Add(doc);
}
// use override that allows to specify onsuccess routine
ARDocumentRelease.ReleaseDoc(newlist, true, null, (ardoc, isAborted) =>
{
//Custom code here, such as create your GL
});
}
);
}
}
I think it's the function
public static void ReleaseDoc(List<ARRegister> list, bool isMassProcess, List<Batch> externalPostList, ARMassProcessDelegate onsuccess)
under ARDocumentRelease businesss logic.

Seeking C# threading clarification

I'm new to threading; in fact I'm not even trying to multi- thread the Windows Forms app I'm working on, but all of my searches on this issue lead me to the topic of multithreading. When debugging in Visual Studio 2010 Express, it seems to "jump around" to use the term I've seen others use to describe the same problem. When I let it run, sometimes it runs as expected, other times it just seems to keep running, getting hung up.
In trying to hone my question, I think I need to figure out:
If the timer class calls a method on a different thread, and there isn't an obvious danger of unpredictable instance values/ state corruption in the executing code (there aren't any conditional checks of instance variables etc), why would that method called by the timer appear to behave unpredictably? To me it seems that the code should run synchronously, and if a different thread is used for part of the process, so be it. I can't see where there is opportunity for thread corruption.
When the program starts, it prompts for the timer to be set to run a data download process. After the procedure runs, the timer is set again to a default time, at the end of the procedure. Consistently, the initial timer setting works, and fires as expected, running the data download process... it's that data download method, somewhere within it it goes awry. The last line of code is what sets the timer again, but I can't tell if it's getting hit while debugging it. (jumping around)..
I've added relevant code below... and I stepped into every procedure in my code from the beginning... they all show current thread id 10. This is up to an including the timer firing off, and stopping at a breakpoint at the very next line to execute, which is the data download process. The current thread at that point: 14. I've built the solution before running it/ trying to debug btw. Any ideas?
public partial class frmTradingAppMain : Form
{
private TradingAppDataRunManager drm;
private void frmTradingAppMain_Shown(object sender, EventArgs e)
{
drm = new TradingAppDataRunManager();
drm.StatusChanged += new DataRunManager.DRMStatusChangeHandler(UpdateFormData);
drm.InitializeOrScheduleDataRun();
}
private void UpdateFormData()
{
this.Invoke(new DataRunManager.DRMStatusChangeHandler(UpdateFormDataImpl));
}
private void UpdateFormDataImpl()
{
lblDataDwnLoadManagerStatus.Text = Convert.ToString(drm.Status);
if (drm.Status == DataRunManager.DRMStatus.Inactive)
{
lblNextScheduledDataDownloadDate.Text = "Date not set.";
lblNextScheduledDataDownloadTime.Text = "Time not set.";
}
else
{
lblNextScheduledDataDownloadDate.Text = drm.DateTimeOfNextScheduledDataRun.ToShortDateString();
lblNextScheduledDataDownloadTime.Text = drm.DateTimeOfNextScheduledDataRun.ToShortTimeString();
}
}
}
public abstract class DataRunManager
{
protected DataRunTimer dataRuntimer;
public delegate void DRMStatusChangeHandler();
public event DRMStatusChangeHandler StatusChanged;
public DRMStatusChangeHandler statusChanged;
public void InitializeOrScheduleDataRun()
{
if (DataRunIsAvailable() && UserWouldLikeToPerformDataRun())
RunMainDataProcedure(null);
else
ScheduleDataRun();
}
public void RunMainDataProcedure(object state)
{
start = DateTime.Now;
Status = DRMStatus.Running;
StatusChanged();
GetDataCollections();
foreach (DataCollection dcl in dataCollectionList)
{
dcl.RunDataCollection();
dcl.WriteCollectionToDatabase();
}
PerformDBServerSideProcs();
stop = DateTime.Now;
WriteDataRunStartStopTimesToDB(start, stop);
SetDataRunTimer(DateTimeOfNextAvailableDR());
}
public void ScheduleDataRun()
{
FrmSetTimer frmSetTimer = new FrmSetTimer(DateTimeOfNextAvailableDataRun);
DateTime currentScheduledTimeOfNextDataRun = DateTimeOfNextScheduledDataRun;
DRMStatus currentStatus= Status;
try
{
frmSetTimer.ShowDialog();
DateTimeOfNextScheduledDataRun = (DateTime)frmSetTimer.Tag;
SetDataRunTimer(DateTimeOfNextScheduledDataRun);
}
catch
{
Status = currentStatus;
DateTimeOfNextScheduledDataRun = currentScheduledTimeOfNextDataRun;
}
}
}
public class DataRunTimer
{
System.Threading.Timer timer;
public DataRunTimer(){}
public void SetNextDataRunTime(TimerCallback timerCallback, DateTime timeToSet)
{
if (timer == null)
timer = new System.Threading.Timer(timerCallback);
TimeSpan delayTime = new TimeSpan(timeToSet.Day - DateTime.Now.Day, timeToSet.Hour - DateTime.Now.Hour, timeToSet.Minute - DateTime.Now.Minute,
timeToSet.Second - DateTime.Now.Second);
TimeSpan intervalTime = new TimeSpan(0, 0, 10);
timer.Change(delayTime, intervalTime);
}
public void DataRunTimerCancel()
{
if (timer != null)
timer.Dispose();
}
}

Outlook 2010 AddIn behaves weirdly when mail invoked from other office client

I really need help with this one.
I have written an adding that adds a some text to the subject line of an email on send it also sets the same value in a property on the email through the PropertyAccessor. This works beautifully when the email is created through the Outlook interface.
The problem I have encountered is when a user is working with excel and decides to send the spreadsheet as an attachment from the Excel 2010 -> File -> Save & Send -> Send as Attachment Menu Item.
This will open the outlook 2010 mail editor as you would expect, the user can address the email and press send as normal and the email will be sent as normal. The problem is that the email editor does not close after sending as you would expect.
I am using the Globals.ThisAddIn.Application.ItemSend event to make my changes to the email. I notice also on debug that this event fires a couple of times when sending. The cancel argument of this event is always false during execution.
Finally found something that seems to work
Developing an Inspector Wrapper for Outlook 2010
In case the link goes dead as they are likely to do
Here's the wrapper
namespace OutlookAddIn
{
// Eventhandler used to correctly clean up resources.
// <param name="id">The unique id of the Inspector instance.</param>
internal delegate void InspectorWrapperClosedEventHandler(Guid id);
// The base class for all inspector wrappers.
internal abstract class InspectorWrapper
{
// Event notification for the InspectorWrapper.Closed event.
// This event is raised when an inspector has been closed.
// The unique ID that identifies an inspector window.
protected InspectorWrapper(Inspector inspector)
{
Id = Guid.NewGuid();
Inspector = inspector;
// Register Inspector events here
((InspectorEvents_10_Event) Inspector).Close += InspectorClose;
((InspectorEvents_10_Event) Inspector).Activate += Activate;
(Inspector).Deactivate += Deactivate;
(Inspector).BeforeMaximize += BeforeMaximize;
(Inspector).BeforeMinimize += BeforeMinimize;
(Inspector).BeforeMove += BeforeMove;
(Inspector).BeforeSize += BeforeSize;
(Inspector).PageChange += PageChange;
// Initialize is called to give the derived wrappers.
Initialize();
}
public Guid Id { get; private set; }
// The Outlook Inspector instance.
public Inspector Inspector { get; private set; }
public event InspectorWrapperClosedEventHandler Closed;
// .ctor
// <param name="inspector">The Outlook Inspector instance that should be handled.</param>
// Event handler for the Inspector Close event.
private void InspectorClose()
{
// Call the Close Method - the derived classes can implement cleanup code
// by overriding the Close method.
Close();
// Unregister Inspector events.
((InspectorEvents_10_Event) Inspector).Close -= InspectorClose;
// Clean up resources and do a GC.Collect().
Inspector = null;
GC.Collect();
GC.WaitForPendingFinalizers();
// Raise the Close event.
if (Closed != null)
{
Closed(Id);
}
}
protected virtual void Initialize()
{}
// Method is called when another page of the inspector has been selected.
// <param name="ActivePageName">The active page name by reference.</param>
protected virtual void PageChange(ref string ActivePageName)
{}
// Method is called before the inspector is resized.
// <param name="Cancel">To prevent resizing, set Cancel to true.</param>
protected virtual void BeforeSize(ref bool Cancel)
{}
// Method is called before the inspector is moved around.
// <param name="Cancel">To prevent moving, set Cancel to true.</param>
protected virtual void BeforeMove(ref bool Cancel)
{}
// Method is called before the inspector is minimized.
// <param name="Cancel">To prevent minimizing, set Cancel to true.</param>
protected virtual void BeforeMinimize(ref bool Cancel)
{}
// Method is called before the inspector is maximized.
// <param name="Cancel">To prevent maximizing, set Cancel to true.</param>
protected virtual void BeforeMaximize(ref bool Cancel)
{}
// Method is called when the inspector is deactivated.
protected virtual void Deactivate()
{}
// Method is called when the inspector is activated.
protected virtual void Activate()
{}
// Derived classes can do a cleanup by overriding this method.
protected virtual void Close()
{}
// This factory method returns a specific InspectorWrapper or null if not handled.
// <param name=”inspector”>The Outlook Inspector instance.</param>
// Returns the specific wrapper or null.
public static InspectorWrapper GetWrapperFor(Inspector inspector)
{
// Retrieve the message class by using late binding.
string messageClass = inspector.CurrentItem.GetType().InvokeMember("MessageClass", BindingFlags.GetProperty,
null, inspector.CurrentItem, null);
// Depending on the message class, you can instantiate a
// different wrapper explicitly for a given message class by
// using a switch statement.
switch (messageClass)
{
case "IPM.Contact":
return new ContactItemWrapper(inspector);
case "IPM.Journal":
return new ContactItemWrapper(inspector);
case "IPM.Note":
return new MailItemWrapper(inspector);
case "IPM.Post":
return new PostItemWrapper(inspector);
case "IPM.Task":
return new TaskItemWrapper(inspector);
}
// Or, check if the message class begins with a specific fragment.
if (messageClass.StartsWith("IPM.Contact.X4U"))
{
return new X4UContactItemWrapper(inspector);
}
// Or, check the interface type of the item.
if (inspector.CurrentItem is AppointmentItem)
{
return new AppointmentItemWrapper(inspector);
}
// No wrapper is found.
return null;
}
}
// Derive a wrapper for each message class/item type.
}
and here is an example override
internal class MailItemWrapper : InspectorWrapper
{
// The Object instance behind the Inspector, which is the current item.
public MailItemWrapper(Inspector inspector)
: base(inspector)
{
// Get the item in the current Inspector.
Item = (MailItem) Inspector.CurrentItem;
// Register Item events.
Item.Open += Item_Open;
Item.Write += Item_Write;
}
public MailItem Item { get; private set; }
// This method is called when the item is visible and the UI is initialized.
// <param name="Cancel">When you set this property to true, the Inspector is closed.</param>
private void Item_Open(ref bool Cancel)
{
// TODO: Implement something
}
// This method is called when the item is saved.
// <param name="Cancel">When set to true, the save operation is cancelled.</param>
private void Item_Write(ref bool Cancel)
{
//TODO: Implement something
}
// The Close method is called when the inspector has been closed.
// Do your cleanup tasks here.
// The UI is gone, cannot access it here.
protected override void Close()
{
// Unregister events.
Item.Write -= Item_Write;
Item.Open -= Item_Open;
// Release references to COM objects.
Item = null;
// Set item to null to keep a reference in memory of the garbage collector.
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
and here is the ThisAddin class
public partial class ThisAddIn
{
// Holds a reference to the Application.Inspectors collection.
// Required to get notifications for NewInspector events.
private Inspectors _inspectors;
// A dictionary that holds a reference to the inspectors handled by the add-in.
private Dictionary<Guid, InspectorWrapper> _wrappedInspectors;
private void ThisAddInStartup(object sender, EventArgs e)
{
_wrappedInspectors = new Dictionary<Guid, InspectorWrapper>();
_inspectors = Globals.ThisAddIn.Application.Inspectors;
_inspectors.NewInspector += WrapInspector;
// Also handle existing Inspectors
// (for example, double-clicking a .msg file).
foreach (Inspector inspector in _inspectors)
{
WrapInspector(inspector);
}
}
// Wrap an Inspector, if required, and store it in memory to get events of the wrapped Inspector.
// <param name="inspector">The Outlook Inspector instance.</param>
private void WrapInspector(Inspector inspector)
{
var wrapper = InspectorWrapper.GetWrapperFor(inspector);
if (wrapper != null)
{
// Register the Closed event.
wrapper.Closed += WrapperClosed;
// Remember the inspector in memory.
_wrappedInspectors[wrapper.Id] = wrapper;
}
}
// Method is called when an inspector has been closed.
// Removes reference from memory.
// <param name="id">The unique id of the closed inspector</param>
private void WrapperClosed(Guid id)
{
_wrappedInspectors.Remove(id);
}
private void ThisAddInShutdown(object sender, EventArgs e)
{
// Clean up.
_wrappedInspectors.Clear();
_inspectors.NewInspector -= WrapInspector;
_inspectors = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
#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()
{
Startup += ThisAddInStartup;
Shutdown += ThisAddInShutdown;
}
#endregion
}
There should be enough there to get people out of trouble if the link is down

Resources