Currently developing a connector DLL to HP's Quality Center. I'm using their (insert expelative) COM API to connect to the server. An Interop wrapper gets created automatically by VStudio.
My solution has 2 projects: the DLL and a tester application - essentially a form with buttons that call functions in the DLL. Everything works well - I can create defects, update them and delete them. When I close the main form, the application stops nicely.
But when I call a function that returns a list of all available projects (to fill a combo box), if I close the main form, VStudio still shows the solution as running and I have to stop it.
I've managed to pinpoint a single function in my code that when I call, the solution remains "hung" and if I don't, it closes well. It's a call to a property in the TDC object get_VisibleProjects that returns a List (not the .Net one, but a type in the COM library) - I just iterate over it and return a proper list (that I later use to fill the combo box):
public List<string> GetAvailableProjects()
{
List<string> projects = new List<string>();
foreach (string project in this.tdc.get_VisibleProjects(qcDomain))
{
projects.Add(project);
}
return projects;
}
My assumption is that something gets retained in memory. If I run the EXE outside of VStudio it closes - but who knows what gets left behind in memory?
My question is - how do I get rid of whatever calling this property returns? Shouldn't the GC handle this? Do I need to delve into pointers?
Things I've tried:
getting the list into a variable and setting it to null at the end of the function
Adding a destructor to the class and nulling the tdc object
Stepping through the tester function application all the way out, whne the form closes and the Main function ends - it closes, but VStudio still shows I'm running.
Thanks for your assistance!
Try to add these 2 lines to post-build event:
call "$(DevEnvDir)..\Tools\vsvars32.bat"
editbin.exe /NXCOMPAT:NO "$(TargetPath)"
Have you tried manually releasing the List object using System.Runtime.InteropServices.Marshal.ReleaseComObject when you are finished with it ?
I suspect some dangling threads.
When this happens, pause the process in the debugger and see what threads are still around.
May be try to iterate the list manually using it's count and Item properties instead of using it's iterator, some thing like:
for (int i=1; i <= lst.Count ; ++i)
{
string projectName = lst.Item(i);
}
It might be the Iterator that keeps it alive and not the list object itself, if not using an iterator might not have a problem.
Related
I am currently experimenting with Visual Studio Extensions.
I need to subscribe to an event that gets called before the actual Debugger is stopped.
Basically I am just Attaching to Managed Process (not running via F5). The problem is that Stop Debugging simply "detaches" the process, and the process continues running after that.
I plan to use this event to notify our process to exit
I have a class that implements IDebugEventCallback2, IVsDebuggerEvents and IVsDebugProcessNotify.
class MyDebugger : IDebugEventCallback2, IVsDebuggerEvents, IVsDebugProcessNotify
Inside this class, there is a member that subscribes to Debugger Events using IVsDebugger's AdviseDebugEventCallback() and AdviseDebuggerEvents() events.
_debugger = Package.GetGlobalService(typeof(SVsShellDebugger)) as IVsDebugger;
if (_debugger != null)
{
_debugger.AdviseDebugEventCallback(this);
_debugger.AdviseDebuggerEvents(this, out _debuggerEventsCookie);
}
I noticed however that the events fired from AdviseDebugEventCallback's Event() handler does not always gets called before the actual Stop Debugging (next few lines after the breakpoint are still executed after I clicked Stopped Debugging). Around 4 or out of 5 times, the event from IDebugCustomEvent110 (riidEvent of 2615D9BC-1948-4D21-81EE-7A963F20CF59) gets called before any line from the attached process gets further executed. I still have to digest the details of the events fired in the Event() handler, but looking at the breakpoints, seems like I could not rely on this as it only works as per my expectation around 4 out of 5 times.
I am currently looking at the BeforeStopDebuggingProcess() method inside IVsDebugProcessNotify.
However, I don't know how to "Subscribe" or "Advice" from this interface.
Any advice how? There isn't much Google result about this topic.
Thank you!
I found something hacky, please comment if this is recommended or not.
I got some hint about the CommandEvents from this post:
How do I know from my VSIX that a build will be followed by a Debug session?
First, I subscribed to the commandEvents of DTE.
DTE dte = await serviceProvider.GetServiceAsync(typeof(DTE)) as DTE;
if (dte != null)
{
events = dte.Events;
commandEvents = events.CommandEvents;
commandEvents.BeforeExecute += OnBeforeExecute;
}
Then, inside OnBeforeExecute, I am hardcoding this particular GUID and ID which I observed to be fired whenever Stop Debugging is clicked (amongst many other events).
If I put Thread.Sleep() of 30 seconds inside this handler, the Stop Button of the Visual Studio freezes for 30 seconds (eventually the entire Visual Studio) :-) The code will resume after 30 seconds of wait.
private void OnBeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
{
if (Guid == "{5EFC7975-14BC-11CF-9B2B-00AA00573819}" && ID == 179)
{
// Stop command is detected
Trace.WriteLine($"[OnBeforeExecute] {Guid} --- {ID} Stop Command Detected");
System.Threading.Thread.Sleep(30000);
}
}
I'm struggling for 4 days now.
There's this C# Process Engine API:
https://www.ibm.com/support/knowledgecenter/en/SSNW2F_5.2.1/com.ibm.p8.pe.dev.doc/web_services/ws_reference.htm
What I need to do is to retrieve the WorkflowNumber when launching the workflow, so later I can find that process in the system.
The issue here is that when you launch it - it returns the LaunchStep (the first step in the workflow) which doesn't have that ID assigned yet - it's null. The only thing available is the LaunchStep's WOBNumber.
In order to assign the Workflow ID to the step, you need to dispatch the step, so I do that:
UpdateStepRequest request = new UpdateStepRequest();
UpdateFlagEnum flag = UpdateFlagEnum.UPDATE_DISPATCH;
request.updateFlag = flag;
request.stepElement = element; // add the launch step
session.Client.updateStep(request);
And here the funny part happens. From this point, there is complately no option to retrieve that, because StepElements are stateless, updateStep() returns nothing and the best part - the LaunchStep is now destroyed in the system, because it's a LaunchStep - it just gets destroyed after the launch.
Any tips would be appreciated!
I'm currently using Calabash framework to automate functional testing for a native Android and IOS application. During my time studying it, I stumbled upon this example project from Xamarin that uses page objects design pattern which I find to be much better to organize the code in a Selenium fashion.
I have made a few adjustments to the original project, adding a file called page_utils.rb in the support directory of the calabash project structure. This file has this method:
def change_page(next_page)
sleep 2
puts "current page is #{current_page_name} changing to #{next_page}"
#current_page = page(next_page).await(PAGE_TRANSITION_PARAMETERS)
sleep 1
capture_screenshot
#current_page.assert_info_present
end
So in my custom steps implementation, when I want to change the page, I trigger the event that changes the page in the UI and update the reference for Calabash calling this method, in example:
#current_page.click_to_home_page
change_page(HomePage)
PAGE_TRANSITION_PARAMETERS is a hash with parameters such as timeout:
PAGE_TRANSITION_PARAMETERS = {
timeout: 10,
screenshot_on_error: true
}
Just so happens to be that whenever I have a timeout waiting for any element in any screen during a test run, I get a generic error message such as:
Timeout waiting for elements: * id:'btn_ok' (Calabash::Android::WaitHelpers::WaitError)
./features/support/utils/page_utils.rb:14:in `change_page'
./features/step_definitions/login_steps.rb:49:in `/^I enter my valid credentials$/'
features/04_support_and_settings.feature:9:in `And I enter my valid credentials'
btn_ok is the id defined for the trait of the first screen in my application, I don't understand why this keeps popping up even in steps ahead of that screen, masking the real problem.
Can anyone help getting rid of this annoyance? Makes really hard debugging test failures, specially on the test cloud.
welcome to Calabash!
As you might be aware, you'll get a Timeout waiting for elements: exception when you attempt to query/wait for an element which can't be found on the screen. When you call page.await(opts), it is actually calling wait_for_elements_exist([trait], opts), which means in your case that after 10 seconds of waiting, the view with id btn_ok can't be found on the screen.
What is assert_info_present ? Does it call wait_for_element_exists or something similar? More importantly, what method is actually being called in page_utils.rb:14 ?
And does your app actually return to the home screen when you invoke click_to_home_page ?
Unfortunately it's difficult to diagnose the issue without some more info, but I'll throw out a few suggestions:
My first guess without seeing your application or your step definitions is that #current_page.click_to_home_page is taking longer than 10 seconds to actually bring the home page back. If that's the case, simply try increasing the timeout (or remove it altogether, since the default is 30 seconds. See source).
My second guess is that the element with id btn_ok is not actually visible on screen when your app returns to the home screen. If that's the case, you could try changing the trait definition from * id:'btn_ok' to all * id:'btn_ok' (the all operator will include views that aren't actually visible on screen). Again, I have no idea what your app looks like so it's hard to say.
My third guess is it's something related to assert_info_present, but it's hard to say without seeing the step defs.
On an unrelated note, I apologize if our sample code is a bit outdated, but at the time of writing we generally don't encourage the use of #current_page to keep track of a page. Calabash was written in a more or less stateless manner and we generally encourage step definitions to avoid using state wherever possible.
Hope this helps! Best of luck.
I'm just discovering the new (to my system) ABAP Debugger Script.
Say this is my program:
* Assume i have the class LCL_SMTH with public methods INCREMENT and REFRESH
DATA: lo_smth TYPE REF TO lcl_smth.
CREATE OBJECT LO_SMTH.
lo_smth->increment( ).
WRITE 'Nothing hapenned'.
Could i get my script to call the REFRESH method after it exits INCREMENT?
I set the script to execute on calling of the INCREMENT method, and it does so. Next I know I have to STEP OUT (F7) -> which I also do - i just don't know how to invoke the REFRESH method.
Debugger script can do exactly what you could do manually. So you can't ... unless you could manually. Since you can jump manually in the debugger, debugger script can as well. So if there is a suitable call to REFRESH somewhere in the code, then you can jump there and back as well.
in the last hours I've struggled with delegates and accessing Windows Forms controls (C++) where I've used this tutorial (the first thread safe method): http://msdn.microsoft.com/en-us/library/ms171728.aspx#Y190
Changing TextBoxes and Labels works perfectly but when I want to show or hide the whole GUI from another thread this fails.
I use the following methode (which is part of the GUI class):
System::Void UI::showUI(boolean value) {
if (this->InvokeRequired) {
SetTextDelegate^ d = gcnew SetTextDelegate(this, &UI::showUI);
this->Invoke(d, gcnew array<Object^> { value });
} else {
if (value == true)
this->Show();
else
this->Hide();
}
}
In the first call the if-clause is true so Invoke is called. But usually the showUI method should be called a second time automatically where the if-clause returns false, but this is not happening. So the GUI is neither shown nor hiden.
Is it necessary to show/hide the GUI with a delegate or can I do it from every possible thread? If a delegate is necessary, why is showUI not executed a second time?
Thanks,
Martin
edit: okay the name SetTextDelegate is not appropriate but this is not the point...
This is a pretty standard case of deadlock, not uncommon with Control::Invoke(). It can only proceed if the UI thread is not busy. Use Debug + Windows + Threads and double-click the Main thread. Look at the call stack to see what it is doing. The typical case is that it is blocking, waiting for the thread to finish the job. That will never happen since the thread can't complete until the Invoke() call returns.
Don't block the UI thread.
Consider using BackgroundWorker, its RunworkerCompleted event is nice to do stuff after the thread completes, removing the need to block.