I am implementing IQueryCancelAutoPlay COM interface and registering it with the Running Objects Table from a Windows Service*.
My problem is that it never gets called when I insert a mass storage device (or any device really). Here's some more information:
My code for registering with the ROT:
Text::string clsIdString = Text::to_string(Com::CLSID_QCAListener);
// remove curly braces
clsIdString = clsIdString.substr(1, clsIdString.length() - 2);
// set registry key to make sure we get notifications from windows
Reg::SetValue(HKEY_LOCAL_MACHINE,
_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoplayHandlers\\CancelAutoplay\\CLSID"),
clsIdString, _T(""));
HRESULT result = S_OK;
// create class moniker ...
CComPtr<IMoniker> moniker;
result = CreateClassMoniker(Com::CLSID_QCAListener, &moniker);
if( !ValidateResult(result, "Error creating class moniker") )
return;
DBG << _T("Getting IRunningObjectTable pointer ...") << std::endl;
// get running oject table ...
CComPtr<IRunningObjectTable> runningObjectTable;
result = GetRunningObjectTable(0, &runningObjectTable);
if( !ValidateResult(result, "Error getting running object table") )
return;
// create an instance of the QCAListener class ...
Com::QCAListener * listenerInstance = new Com::QCAListener();
if(!ValidateResult( listenerInstance != 0,
"Error creating QueryCancelAutoplayListener"))
return;
// ... and set the pointer in the _qcaListener variable
CComPtr<IQueryCancelAutoPlay> qcaListener;
listenerInstance->QueryInterface(IID_IQueryCancelAutoPlay, reinterpret_cast<void**>(&qcaListener));
DBG << _T("Registering IQueryCancelAutoPlay with ROT ...") << std::endl;
result = runningObjectTable->Register(
ROTFLAGS_REGISTRATIONKEEPSALIVE,
listenerInstance,
moniker,
&_qcaRegistration);
ValidateResult(result, "Error registering QueryCancelAutoplayListener with the ROT");
runningObjectTable->Register returns S_OK, and at the end of the code block's execution the ref-count for listenerInstance is 1 (if I remove the call to runningObjectTable->Register completely, the ref-count remains 0 when qcaListener goes out of scope so this means an instance of my class remains active in the ROT).
More details: In development, my service runs with my account credentials (local administrator). Although this will probably change, it should work as it is with the current configuration.
Can anyone shed any light on this?
*- I know the documentation says I shouldn't implement IQueryCancelAutoPlay in a service but I need to do this for various reasons (business requirement, etc).
I figured it out (for those who stumble upon this answer when having a similar problem):
The service runs under a different window station and a different desktop. When the IQueryCalcelAutoPlay implementation is registered in the ROT this is done for a different desktop.
The current user's desktop shell (explorer) will not find this registration when a new USB device is inserted (as it is not registered with the current desktop).
Related
I am using Visual Studio 2013 and making MFC Dialog based application. I am running into strange issue with Kill Focus of Edit Control.
Please see below:
==========================================================================
In my application, I have two Edit Controls on Dialog Box.
1st Edit Control -> IDC_EDIT_QUALITY1
2nd Edit Control -> IDC_EDIT_QUALITY2
I have handled both's EN_KILLFOCUS event to validate the value.
BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
ON_EN_KILLFOCUS(IDC_EDIT_QUALITY1, &CTestDlg::OnQuality1EditKillFocus)
ON_EN_KILLFOCUS(IDC_EDIT_QUALITY2, &CTestDlg::OnQuality2EditKillFocus)
END_MESSAGE_MAP()
void CTestDlg::OnQuality1EditKillFocus()
{
ValidateQualityParams(IDC_EDIT_QUALITY1);
}
void CTestDlg::OnQuality2EditKillFocus()
{
ValidateQualityParams(IDC_EDIT_QUALITY2);
}
#define MIN_QUALITY_VALUE 1
#define MAX_QUALITY_VALUE 100
void CTestDlg::ValidateQualityParams(int qualityParamID)
{
CString strQuality1;
if (IDC_EDIT_QUALITY1 == qualityParamID)
{
m_ctrlQuality1.GetWindowText(strQuality1);
if ((_ttoi(strQuality1) < MIN_QUALITY_VALUE) || (_ttoi(strQuality1) > MAX_QUALITY_VALUE))
{
CString strMessage;
strMessage.Format(_T("Quality1 value must be between %d to %d."), MIN_QUALITY_VALUE, MAX_QUALITY_VALUE);
**AfxMessageBox(strMessage);**
m_ctrlQuality1.SetSel(0, -1);
m_ctrlQuality1.SetFocus();
return;
}
}
CString strQuality2;
if (IDC_EDIT_QUALITY2 == qualityParamID)
{
m_ctrlQuality2.GetWindowText(strQuality2);
if ((_ttoi(strQuality2) < MIN_QUALITY_VALUE) || (_ttoi(strQuality2) > MAX_QUALITY_VALUE))
{
CString strMessage;
strMessage.Format(_T("Quality2 value must be between %d to %d."), MIN_QUALITY_VALUE, MAX_QUALITY_VALUE);
AfxMessageBox(strMessage);
m_ctrlQuality2.SetSel(0, -1);
m_ctrlQuality2.SetFocus();
return;
}
}
}
Now, the issue happens when, after changing the value in 1st Edit Control (IDC_EDIT_QUALITY1), say entering 0 in it and pressing TAB key, the flow goes as below:
void CTestDlg::OnQuality1EditKillFocus() is called.
It calls ValidateQualityParams(IDC_EDIT_QUALITY1)
Inside ValidateQualityParams, it goes to if (IDC_EDIT_QUALITY1 == qualityParamID) condition.
As the value I entered is less than MIN_QUALITY_VALUE, so it shows the Message by calling AfxMessageBox.
- Now, even from the callstack of AfxMessageBox, it hits void CTestDlg::OnQuality2EditKillFocus() internally.
Although callstack of OnQuality1EditKillFocus is NOT finished yet, OnQuality2EditKillFocus gets called from the callstack of AfxMessageBox.
I don't understand the cause of this issue. Has anyone encountered such issue before?
In my resource.h, I have two distinct values for IDC_EDIT_QUALITY1 and IDC_EDIT_QUALITY2
#define IDC_EDIT_QUALITY1 1018
#define IDC_EDIT_QUALITY2 1020
Please help on this issue.
I believe the EN_KILLFOCUS notification for the IDC_EDIT_QUALITY2 control you are receiving is caused not by the m_ctrlQuality1.SetFocus() call, but instead by the AfxMessageBox() call.
When you press the [Tab] key IDC_EDIT_QUALITY1 loses the focus, and IDC_EDIT_QUALITY2 gets the focus. Then you receive the EN_KILLFOCUS notification for IDC_EDIT_QUALITY1. You display the error-message, which causes the application to "yield" (start processing messages again), while the message-box is displayed. The m_ctrlQuality1.SetFocus() call won't take place before the AfxMessageBox() returns, ie before you close the message-box, and therefore the EN_KILLFOCUS notification for IDC_EDIT_QUALITY2 can't be the result of that call. I guess it's the result of displaying the message-box (IDC_EDIT_QUALITY2 has got the focus, but the message-box makes it lose it).
You may work around it by adding a memeber variable, as Staytuned123 suggested, but in a different setting: name it, say m_bKillFocusProcessing, and set it to TRUE while you are processing ANY EN_KILLFOCUS notification (AfxMessageBox() plus SetFocus()), and to FALSE when you are done processing it; if it's already TRUE exit without doing anything. That is, only one EN_KILLFOCUS notification may be processed at a time.
However, such a user-interface (displaying a message-box on exiting a field) is rather weird. And why reinvent the wheel and not instead use the DDX/DDV feature, which MFC already offers? You can define member variables associated with controls, and perform various checks, including range-check. Call UpdateData(TRUE) to perform the checks (for all controls on the dialog) and transfer the data to the member variables. Or you can put some error-displaying controls (usually in red color), activated when an error is found, like in .net or the web.
When you pressed TAB key, IDC_EDIT_QUALITY2 got focus. But because value entered was out of bound, the program called m_ctrlQuality1.SetFocus(), which in turn caused OnQuality2EditKillFocus() to get called.
Add a member variable says m_bQuality1OutOfBound and set it to true right before calling m_ctrlQuality1.SetFocus(). In OnQuality2EditKillFocus(), when m_bQuality1OutOfBound is true, set it to false and don't call ValidateQualityParams(IDC_EDIT_QUALITY2).
Some questions about KeSetSystemAffinityThread function, since MSDN is quite laconic.
NOTE: I can't use the more complete KeSetSystemAffinityThreadEx because I must still support Windows XP.
1) How can I restore the previous affinity? The function does not return the old value, how can I obtain it?
2) Is it true that passing 0 to the function restores the default system affinity? I have found such assertion in some forums, but I can't find it in official MS documentation.
3) Is the new thread's system affinity mask maintained after a return to user mode, or is it restored to the default each time the thread enters in system mode?
4) What happens if previous system affinity mask is not restored?
(I'd rather post four different questions, but they seem to me too interdependent)
Use the undocumented KeRevertToUserAffinityThread(void) in WinXP. A quick search yields little information about the API but I found an implementation of the same function in ReastOS :
ReactOS KeRevertToUserAffinityThread
It is rather simple so I copy & paste it here:
VOID NTAPI KeRevertToUserAffinityThread ( VOID )
{
KIRQL OldIrql;
PKPRCB Prcb;
PKTHREAD NextThread, CurrentThread = KeGetCurrentThread();
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
ASSERT(CurrentThread->SystemAffinityActive != FALSE);
/* Lock the Dispatcher Database */
OldIrql = KiAcquireDispatcherLock();
/* Set the user affinity and processor and disable system affinity */
CurrentThread->Affinity = CurrentThread->UserAffinity;
CurrentThread->IdealProcessor = CurrentThread->UserIdealProcessor;
CurrentThread->SystemAffinityActive = FALSE;
/* Get the current PRCB and check if it doesn't match this affinity */
Prcb = KeGetCurrentPrcb();
if (!(Prcb->SetMember & CurrentThread->Affinity))
{
/* Lock the PRCB */
KiAcquirePrcbLock(Prcb);
/* Check if there's no next thread scheduled */
if (!Prcb->NextThread)
{
/* Select a new thread and set it on standby */
NextThread = KiSelectNextThread(Prcb);
NextThread->State = Standby;
Prcb->NextThread = NextThread;
}
/* Release the PRCB lock */
KiReleasePrcbLock(Prcb);
}
/* Unlock dispatcher database */
KiReleaseDispatcherLock(OldIrql);
}
Note the function takes no argument and just restore the affinity from some elements in the currrent KTHREAD struct. I guess this answer your question 1 & 2. Just call this function with no argument. I have done a test in 32bit WinXP and confirmed this. Question 4 is simple, your thread will continue to run using the processor affinity your've set.
I have no idea to your question 3. But most likely a switch between user and kernel mode has no effect on the current processor affinity in effect since this is something stored in the KTHREAD struct.
I have a website that I need to perform a Load Test on. I tried this with one user logging in and clicking around then logging out. It worked ok but now I need to try with 50 users. Initial user count is 5, increasing by 5 every 20 seconds up to a max user count of 50.
Sessions are managed so I need 50 unique logins, I do have a set of users with associated passwords. I tried doing some searching and I cannot figure out how to get the test to run with the set of users that I have.
Anyone on here have any experience with it?
Here's some helpful information considering your question: https://msdn.microsoft.com/en-us/library/dn250793.aspx
It's about using load testing in Visual Studio Ultimate to find performance issues before you release your app.
In Visual Studio Ultimate Trial version, the virtual user count is limited to 250.
If you want to use exactly as many virtual users as you have user accounts in your test data, you could use a web test plugin like this:
using Microsoft.VisualStudio.TestTools.WebTesting;
using System.ComponentModel;
namespace Plugins
{
[DisplayName("Lock Data Table Row to Virtual User Id")]
[Description("Makes each virtual user use the same data row as their user id. "
+ "Only works on first table of first data source. \r\n"
+ "LoadTest > Scenario > Percentage of New Users must be set to 0.")]
public class LockDataTableRowToVirtualUserIdWebTestPlugin : WebTestPlugin
{
public override void PreWebTest(object sender, PreWebTestEventArgs e)
{
int id = e.WebTest.Context.WebTestUserId;
// correct discrepancy (WebTests start at id 1, LoadTests start at id 0)
if (!e.WebTest.Context.ContainsKey("$LoadTestUserContext")) id -= 1;
int rows = e.WebTest.GetDataTableRowCount(e.WebTest.DataSources[0].Name, e.WebTest.DataSources[0].Tables[0].Name);
if (id > rows - 1) // not enough rows
throw new WebTestException("Not enough rows to provide all users with unique data; id=" + id + " rows=" + rows);
e.WebTest.MoveDataTableCursor(e.WebTest.DataSources[0].Name, e.WebTest.DataSources[0].Tables[0].Name, id);
}
}
}
Requires "Percentage of New Users" setting in the Load Test Scenario properties be set to 0, which keeps the virtual user ids constant for each virtual user. Otherwise, new virtual users will get new ids that exceed the data rows.
Could easily be enhanced to work on named DataSources/DataTables via properties.
I have records that have an index attribute to maintain their position in relation to each other.
I have a plugin that performs a renumbering operation on these records when the index is changed or new one created. There are specific rules that apply to items that are at the first and last position in the list.
If a new (or existing changed) item is inserted into the middle (not technically the middle...just somewhere between start and end) of the list a renumbering kicks off to make room for the record.
This renumbering process fires in a new execution pipeline...We are updating record D. When I tell record E to change (to make room for D) that of course fires the plugin on update message.
This renumbering is fine until we reach the end of the list where the plugin then gets into a loop with the first business rule that maintains the first and last record differently.
So I am trying to think of ways to pass a flag to the execution context spawned by the renumbering process so the recursion skips the boundary edge business rules if IsRenumbering == true.
My thoughts / ideas:
I have thought of using the Depth check > 1 but that isn't a reliable value as I can't explicitly turn it on or off....it may happen to work but that is not engineering a solid solution that is hoping nothing goes bump. Further a colleague far more knowledgeable than I said that when a workflow calls a plugin the depth value is off and can't be trusted.
All my variables are scoped at the execute level so as to avoid variable pollution at the class level....However if I had a dictionary object, tuple, something at the class level and one value would be the thread id and the other the flag value then perhaps my subsequent execution context could check if the same owning thread id had any values entered.
Any thoughts or other ideas on how to pass context information to a new pipeline would be greatly appreciated.
Per Nicknow sugestion I tried sharedvariables but they seem to be going out of scope...:
First time firing post op:
if (base.Stage == EXrmPluginStepStage.PostOperation)
{
...snip...
foreach (var item in RenumberSet)
{
Context.ParentContext.SharedVariables[recordrenumbering] = "googly";
Entity renumrec = new Entity("abcd") { Id = item.Id };
#region We either add or subtract indexes based upon sortdir
...snip...
renumrec["abc_indexfield"] = TmpIdx + 1;
break;
.....snip.....
#endregion
OrganizationService.Update(renumrec);
}
}
Now we come into Pre-Op of the recursion process kicked off by the above post-op OrganizationService.Update(renumrec); and it seems based upon this check the sharedvariable didn't carry over...???
if (!Context.SharedVariables.Contains(recordrenumbering))
{
//Trace.Trace("Null Set");
//Context.SharedVariables[recordrenumbering] = IsRenumbering;
Context.SharedVariables[recordrenumbering] = "Null Set";
}
throw invalidpluginexception reveals:
Sanity Checks:
Depth : 2
Entity: ...
Message: Update
Stage: PreOperation [20]
User: 065507fe-86df-e311-95fe-00155d050605
Initiating User: 065507fe-86df-e311-95fe-00155d050605
ContextEntityName: ....
ContextParentEntityName: ....
....
IsRenumbering: Null Set
What are you looking for is IExecutionContext.SharedVariables. Whatever you add here is available throughout the entire transaction. Since you'll have child pipelines you'll want to look at the ParentContext for the value. This can all get a little tricky, so be sure to do a lot of testing - I've run into many issues with SharedVariables and looping operations in Dynamics CRM.
Here is some sample (very untested) code to get you started.
public static bool GetIsRenumbering(IPluginExecutionContext pluginContext)
{
var keyName = "IsRenumbering";
var ctx = pluginContext;
while (ctx != null)
{
if (ctx.SharedVariables.Contains(keyName))
{
return (bool)ctx.SharedVariables[keyName];
}
else ctx = ctx.ParentContext;
}
return false;
}
public static void SetIsRenumbering(IPluginExecutionContext pluginContext)
{
var keyName = "IsRenumbering";
var ctx = pluginContext;
ctx.SharedVariables.Add(keyName, true);
}
A very simple solution: add a bit field to the entity called "DisableIndexRecalculation." When your first plugin runs, make sure to set that field to true for all of your updates. In the same plugin, check to see if "DisableIndexRecalculation" is set to true: if so, set it to null (by removing it from the TargetEntity entirely) and stop executing the plugin. If it is null, do your index recalculation.
Because you are immediately removing the field from the TargetEntity if it is true the value will never be persisted to the database so there will be no performance penalty.
I am just working my way through the location services for the first time and everything appears to be working in that it correctly finds my location but I am having trouble extracting the coordinates.
The docs states that CLLocation has a "Coordinates" property and the compiler is happy with this piece of code. However at runtime the CLLocation only appears to return a string description.
I start the location manager
_locationManager = new CLLocationManager ();
_locationManager.DesiredAccuracy = 1000;
// handle the updated location method and update the UI
_locationManager.LocationsUpdated += (object sender, CLLocationsUpdatedEventArgs e) => {
UpdateLocation (e.Locations [e.Locations.Length - 1], _destinationLatitude, _destinationLongitude);
};
if (CLLocationManager.LocationServicesEnabled)
_locationManager.StartUpdatingLocation ();
The event fires correctly
static public void UpdateLocation (CLLocation current, Double destinationLat, Double destinationLng)
{
//Make the start pairing
string start = current.Coordinate.Latitude.ToString() + "," + current.Coordinate.Longitude.ToString();
//Make the destination pairing
string destination = destinationLat.ToString() + "," + destinationLng.ToString();
}
However the app just crashes out. Catching it on a breakpoint I see the following which only appears to have a description property that contains.
Description "<+50.58198902,-3.67661728> +/- 65.00m (speed -1.00 mps / course -1.00) # 25/07/2013 13:11:28 British…" string
I can obviously extract the lat/lng from this text field but I get the feeling I shouldn't need to do this. Any help appreciated.
I moved the exact same code into a different controller and it worked fine. The only difference between the two controllers was that the failing controller was using the monotouch dialog reflection api to bind the screen elements. I can't see why this would make any difference but it is the only difference between the two controllers. Everything is working now, I will try to reproduce in a smaller sample if I get the time.