I'm having a problem using IApplicationAssociationRegistration to check the default email client. In the user context everything is fine, but from a service running in the system context the wrong default client is being returned as it seems to be picking up values from the system user rather than the current logged in user.
Here are the steps I take:
1) Call CoInitialize and CoInitializeSecurity for impersonation.
2) Call DuplicateTokenEx to get a security token for SecurityImpersonation of the logged in user.
3) Call ImpersonateLoggedOnUser with the token.
4) Call CoCreateInstance to create an instance of IApplicationAssociationRegistration. I get S_OK returned and an instance pointer.
5) Call CoSetProxyBlanket for both the instance pointer I got from step (4) and the IUnknown pointer. Again I get S_OK returned.
6) Call the method IApplicationAssociationRegistration::QueryAppIsDefault for Outlook using the instance pointer I got from step (4). Again I get S_OK returned, but in the system context I get TRUE returned, and in the user context I correctly get FALSE returned. If I manually modify the UrlAssociations/mailto/UserChoice/ProgId value for HKEY_USERS/.DEFAULT in regedit and call again, it picks up the new value.
7) Similarly if I call SetAppAsDefault, it seems to set the associations in the system context, rather than the user context as I want.
If I put steps 4 to 7 into a console application and run this from the service using CreateProcessAsUser, then it works fine. But I would rather avoid having to do this.
Any help would be appreciated.
Related
The purpose is to create a new process in session 0 from a process in non 0 console session.
I know some methods that fulfill the purpose, but I want to know why the method described below does not, despite msdn says it should work.
unsigned FindProcessInSession(unsigned SessionId,const wchar_t*ProcessName)
{
PWTS_PROCESS_INFOW pinfo;DWORD Count,Result=0;
if(WTSEnumerateProcessesW(WTS_CURRENT_SERVER_HANDLE,0,1,&pinfo,&Count)){
for(unsigned i=0;i<Count;++i)if(pinfo[i].SessionId==SessionId&&_wcsicmp(pinfo[i].pProcessName,ProcessName)==0){
Result=pinfo[i].ProcessId;break;
}
WTSFreeMemory(pinfo);
}
return Result;
}
int main()
{
HANDLE hProcess=OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,0,FindProcessInSession(0,L"smss.exe")),ProcessToken,NewToken;
if(hProcess&&OpenProcessToken(hProcess,TOKEN_DUPLICATE,&ProcessToken)&&DuplicateTokenEx(ProcessToken,MAXIMUM_ALLOWED,0,SecurityImpersonation,TokenImpersonation,&NewToken)){
static STARTUPINFOW si={sizeof(STARTUPINFOW)};PROCESS_INFORMATION pi;DWORD SessionId,l;
printf("GetTokenInformation %d\n",GetTokenInformation(NewToken,TokenSessionId,&SessionId,sizeof SessionId,&l));
printf("SessionId %d\n",SessionId);
printf("CreateProcessWithTokenW %d\n",CreateProcessWithTokenW(NewToken,0,L"c:\\windows\\system32\\cmd.exe",0,0,0,0,&si,&pi));
}
}
During testing on my pc,GetTokenInformation successfully output SessionId=0 and CreateProcessWithTokenW created a new process in SYSTEM username, with all privileges from smss.exe. but the new process still ran in whatever session the calling process was in.
msdn on CreateProcessWithTokenW notes
Terminal Services: The process is run in the session specified in the token. By default, this is the same session that called LogonUser. To change the session, use the SetTokenInformation function.
Apparantly the secondary logon service CreateProcessWithTokenW relies on not does not follow the documentation
CreateProcessWithTokenW get SessionId of caller and set this SessionId in token (as side effect - token was modified after CreateProcessWithTokenW. you can call GetTokenInformation again after CreateProcessWithTokenW and view that now already not 0 here. so - CreateProcessWithTokenW can not be used for run process in another session. need use CreateProcessAsUserW. more research here
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 having a problem associating a browser_id to a session when using Products.BeakerSessionDataManager. I'm working on Plone 5.
As far as I understand Zope sessions, as soon as .getSessionData() is called on a session data manager, a session data container is created if it did not exist. Furthermore, this data will contain a token, which is the same as the browser_id associated with the browser making the request. And finally, a cookie is set on the response with the name _ZopeId (and the value is the same as the token). Thus, when I use the default session data manager that come with Zope, I get this:
ipdb> context.session_data_manager.getSessionData()
id: 14737473151418102847, token: 38878600A7nh90DE9ao, content keys: []
However, when I use Products.BeakerSessionDataManager, the same call gives me this:
ipdb> context.session_data_manager.getSessionData()
{'_accessed_time': 1473745441.437582, '_creation_time': 1473745441.437582}
Moreover, no cookie is set.
Perusing some old Zope docs, I found a reference to getContainerKey(), so I thought that might get me the browser_id. However, the returned value is different on every request, so that does not work. Also, calling .getBrowserIdManager().getBrowserId() on the session_data_manager throws an error, because Beaker does not support browser id managers.
I want to set a cookie, and I want a token. I'm doing this so that I can identify anonymous clients in a voting application, so that they will not cast multiple votes (at least not in the same session - there are other mechanisms to allow voting only when certain other conditions are met).
Am I misunderstanding the machinery, or am I missing something?
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.
The MSDN CreatMutex() documentation (http://msdn.microsoft.com/en-us/library/ms682411%28VS.85%29.aspx) contains the following remark near the end:
Two or more processes can call CreateMutex to create the same named mutex. The first process actually creates the mutex, and subsequent processes with sufficient access rights simply open a handle to the existing mutex. This enables multiple processes to get handles of the same mutex, while relieving the user of the responsibility of ensuring that the creating process is started first. When using this technique, you should set the bInitialOwner flag to FALSE; otherwise, it can be difficult to be certain which process has initial ownership.
Can somebody explain the problem with using bInitialOwner = TRUE?
Earlier in the same documentation it suggests a call to GetLastError() will allow you to determine whether a call to CreateMutex() created the mutex or just returned a new handle to an existing mutex:
Return Value
If the function succeeds, the return value is a handle to the newly created mutex object.
If the function fails, the return value is NULL. To get extended error information, call GetLastError.
If the mutex is a named mutex and the object existed before this function call, the return value is a handle to the existing object, GetLastError returns ERROR_ALREADY_EXISTS, bInitialOwner is ignored, and the calling thread is not granted ownership. However, if the caller has limited access rights, the function will fail with ERROR_ACCESS_DENIED and the caller should use the OpenMutex function.
Using bInitialOwner combines two steps into one: creating the mutex and acquiring the mutex. If multiple people can be creating the mutex at once, the first step can fail while the second step can succeed.
As the other answerers mentioned, this isn't strictly a problem, since you'll get ERROR_ALREADY_EXISTS if someone else creates it first. But then you have to differentiate between the cases of "failed to create or find the mutex" and "failed to acquire the mutex; try again later" just by using the error code. It'll make your code hard to read and easier to screw up.
In contrast, when bInitialOwner is FALSE, the flow is much simpler:
result = create mutex()
if result == error:
// die
result = try to acquire mutex()
if result == error:
// try again later
else:
// it worked!
Well, not sure if there's a real problem. But if you set the argument to TRUE in both processes then you have to check the value of GetLastError() to check if you actually ended up having ownership. It will be first-come-first serve. Useful perhaps only if you use a named mutex to implement a singleton process instance.
The flag is used to create the mutex in an owned state - the successful caller will atomically create the synchronisation object and also acquire the lock before returning in the case that the caller needs to be certain that no race condition can form between creating the object and acquiring it.
Your protocol will determine whether you ever need to do this in one atomic operation.