CoInitializeSecurity cannot succeeded when using TChromium (CEF3) - c++

I have an application that is running a chromium client browser, and at some point I need to execute WMI code to access some device information, but it fails everytime. It is working only when the application is not using TChromium object. Possible TChromium(CEF3) Initializes the COM library, and only one instance is allowed on the current thread. I read that application should use CoInitializeEx with COINIT_APARTMENTTHREADED instead of CoInitialize.
It is possible to access COM library and CoInitializeSecurity when using TChromium (CEF3) in one application? If yes, how to do it?
Below is what I want to achive:
CoUninitialize();
CoInitialize(NULL);
if(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0) == S_OK)
{
// cannot get here, CoInitializeSecurity fails
... need to execute WMI code using IWbemLocator, IWbemServices ...
}

COM can be initialized only 1 time per thread. CoInitialize/Ex() can be called multiple times per thread (with corresponding CoUninitialize() calls for every successful CoInitialize/Ex() call), but COM will only be initialized on the first call, and subsequent calls will return either S_FALSE or RPC_E_CHANGED_MODE if COM has already been initialized on the calling thread.
To solve your issue, try moving your WMI code to a separate worker thread, then you have total control over how you want to initialize COM for that thread, completely separate from how COM is initialized on the main UI thread. Have your main thread create the WMI thread when needed and wait for it to terminate, then the WMI thread can query the device info and pass it back to the main thread.

Related

User process can't see global shared memory created by service

I have a Windows service (running in the system process) and a desktop application that need to share a configuration structure. The data originates in the app, but the user process doesn't have permission to create a global memory object so I create it when the service starts using CreateFileMapping() and a DACL based on this answer. This appears to work fine: I get a non-null handle back from CreateFileMapping() and GetLastError() is 0. The problem is that the app can't see the object -- OpenFileMapping() returns a NULL handle and ERROR_FILE_NOT_FOUND -- and I also can't see it if I manually browse the global objects with WinObj. What's keeping my object from being visible?
SECURITY_ATTRIBUTES security;
ZeroMemory(&security, sizeof(security));
security.nLength = sizeof(security);
ConvertStringSecurityDescriptorToSecurityDescriptor(
"D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GWGR;;;IU)",
SDDL_REVISION_1,
&security.lpSecurityDescriptor,
NULL);
HANDLE hFile = CreateFileMapping(INVALID_HANDLE_VALUE, &security, PAGE_READWRITE, 0, 1024*4, "Global\\gCONFIGXFILE");
DWORD fileMappingResult = GetLastError();
if (hFile)
{
CloseHandle(hFile);
}
LocalFree(security.lpSecurityDescriptor);
Your service is closing its handle to the file mapping immediately after creating it, thus the mapping is being destroyed before the app has a chance to open its handle to the mapping. Your service needs to leave its handle to the mapping open, at least until after the app has opened its handle to the mapping.
Since you are sharing configuration, you should probably be creating the mapping at service start and leave it open until service stop. You could use a named event via CreateEvent() to let the service tell the app when the mapping has actually been created, and maybe use another named event whenever the content of the mapping is changed by either process.

Restarting a process from another process

I have two processes: ProcessA and ProcessB.
When i launch my application, i call ProcessA which uses CreateProcess() to launch ProcessB. ProcessA is killed by ProcessB when my application receives command A. Likewise, ProcessB should relaunch ProcessA when it receives command B.
Where i am stuck on is on the process of relaunching ProcessA. Since ProcessA has the code to relaunch ProcessB, i cannot stop it from relaunching another instance of ProcessB. Ideally, i want to have only 1 instance of ProcessB.
For creating ProcessB from ProcessA, i have the following code:
for(int i32Index = 0; i32Index < NUM_PROCESS; i32Index++)
{
wcscpy(wcPath,Directorypath.c_str());
wcscat(wcPath,wcProcess[i32Index]);
RETAILMSG(1,(_T("Path:%s\r\n"),wcPath));
bCreateProcessSuccess = CreateProcess(wcPath, // No module name (use command line)
NULL, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) ; // Pointer to PROCESS_INFORMATION structure
if(bCreateProcessSuccess == FALSE)
{
RETAILMSG(1,(_T("Create process failed:%d\r\n"),GetLastError()));
}
else
{
RETAILMSG(1,(_T("Loading Exes\r\n")));
}
Pretty straightforward, basic code. I basically repeat this in ProcessB, but so that it creates ProcessA.
Now, im stuck on how i would be able to implement the condition to launch ProcessA without it launching ProcessB again. I initially thought of using a flag, but that flag would be reset since launching ProcessA would reset the flag as it is local to the function.
Also, to clarify: this is in windows embedded compact environment so both processes exist as different subprojects so to access ProcessA from ProcessB would require IPC.
My next idea was to use CreateEvent() with WaitForSingleObject() to check if the event is signaled, but i realized that the wait duration would have to be infinite, which would cause an issue the first time i launch my application.
So, is there any type of windows(wince) api that would solve this? (Or some kind of fancy coding i cannot think of?)
There are a few ways you could do this but two options are:
When you launch ProcessA again, pass it a command line argument using the lpCommandLine parameter (e.g. /nolaunch). ProcessA can then get its command line using GetCommandLine when it starts up and see if it contains the /nolaunch string.
In both ProcessA and ProcessB, use the CreateSemaphore or CreateMutex function to create a named semaphore/mutex. In ProcessB, that's all you have to do - just make sure you don't close the handle until the process exits. In ProcessA, after creating the semaphore/mutex check if GetLastError() returns ERROR_ALREADY_EXISTS - this indicates that ProcessB still has the semaphore/mutex open (and therefore is already running).
There are multiple ways you can sole this:
1. Holding a mutex
In processB you can hold a named mutex and lock it. When processB will be created, it will try to lock the mutex and fail, and than it will kill itself. You can also check if the mutex is locked in processA and prevent the processB creation from the beginning.
2. Sending an argument to process creation
CreateProcess supports sending command line arguments to the created process via the second argument. You can use it as an indicator to whether you should create processB or not.
3. Going through the process list
You can go through the current process list and check if ProcessB is already running. Might want to look into Taking a Snapshot and Viewing Processes.

WM_PAINT and non finished COM calls (ATL OOP Server "Deadlock")

We have developed an STA ATL COM OOP Server and all works fine, almost. We are facing a problem: As the COM client internally gets the result of any COM call through a windows message the WM_PAINT message (or any other message i guess) can be processed while waiting for an answer of a COM call. That can be a problem in itself, but the big problem is that until previous COM call finishes all the calls to the server will fail (HRESULT=0x80010005), and this is quite a big issue as its happening really often in our application. We cant remove the COM calls from the paint.
I've been researching quite a bit about this and could not find anything regarding it (aside from this 2006 article that states the problem and some solutions that cant be applied in our case), but for what I see not only the WM_PAINT will be dangerous, any call to the server we perform inside of any windows event (message) will potentially cause the same problem.
So basically we can have different solutions but no clue about which COM methods to use or how:
1- A method that waits until last COM call is processed and value returned
2- A method to know if there is any pending to answer call in the server and a method to process the COM answers (all called from the client)
3- Know if we can implement an IMessageFilter class in the client and how to handle it and process the calls and so.
Thank you!
As the COM client internally gets the result of any COM call through a windows message the WM_PAINT message (or any other message i guess) can be processed while waiting for an answer of a COM call.
There is nothing connecting COM calls with WM_PAINT processing. The two tasks exist concurrently, but as you chose STA to be the model, both these tasks run on the same thread and might be blocking one another.
There is little you can do about painting itself, since you eventually will have a message handler to do the painting. However you can alter your COM server, and your paint handler to not interfere with COM.
You don't need to do COM calls right from WM_PAINT. Structure your server so that it posts all UI updates asynchronously and paint handler just uses most recent data available.
Also you can move your server to another apartment, STA or MTA, so that it does not share thread with UI and run in parallel.
We have fixed the problem implementing an IMessageFilter class in the client project (C++):
MessageFilter.h:
#include <atlbase.h>
#include <atlcom.h>
namespace SDKCOMSrvInterface
{
class MessageFilter : public CComObjectRootEx<CComSingleThreadModel>, public IMessageFilter
{
BEGIN_COM_MAP(MessageFilter)
COM_INTERFACE_ENTRY(IMessageFilter)
END_COM_MAP()
// Implement IMessageFilter methods here
STDMETHODIMP_(DWORD) HandleInComingCall(
DWORD dwCallType,
HTASK threadIDCaller,
DWORD dwTickCount,
LPINTERFACEINFO lpInterfaceInfo)
{
return E_NOTIMPL;
}
STDMETHODIMP_(DWORD) RetryRejectedCall(
HTASK threadIDCallee,
DWORD dwTimeOut,
DWORD dwRejectType)
{
return SERVERCALL_RETRYLATER;
}
STDMETHODIMP_(DWORD) MessagePending(
HTASK threadIDCallee,
DWORD dwTickCount,
DWORD dwPendingType)
{
return PENDINGMSG_WAITDEFPROCESS;
}
};
}
And registering it just after CoInitialize(NULL):
CComObject<MessageFilter>* l_MessageFilter = NULL;
CComObject<MessageFilter>::CreateInstance(&l_MessageFilter);
CComPtr<IMessageFilter> l_OldMessageFilter;
hr = CoRegisterMessageFilter(l_MessageFilter, &l_OldMessageFilter);
This will ensure that if we try to call the server from the client and the server is busy, the COM call will be retried until the server processes the previous call, which is exactly what is needed to solve the concurrency problem.

Injecting Ctrl+C into target process

I have a process that has a CtrlBreak handler by calling SetConsoleCtrlHandler. This handler listens for CTRL_BREAK_EVENT and performs some action (without quitting). This process is not attached to a console. Let's call this the target process.
Next, I have written a separate program which takes a PID and I'd like to start a remote thread at the address of kernel*!CtrlRoutine so that the CtrlBreak handler of the target process is executed, e.g.:
hRemoteThread=CreateRemoteThread(hRemoteProc, NULL, 0,
(LPTHREAD_START_ROUTINE)dwEntryPoint,
(void *)CTRL_BREAK_EVENT, CREATE_SUSPENDED, NULL);
ResumeThread(hRemoteThread);
The problem is, how do I find the address of kernel*!CtrlRoutine in the remote process (dwEntryPoint)?
I saw an example where a program registered its own CtrlBreakHandler, then walked up the stack using __asm to get the address, but this code doesnt work correctly on Windows 2008 Server.
Just to note, I cannot recompile the target process, so I have to do this without modifying the target process.
Microsoft provides a GenerateConsoleCtrlEvent function for this purpose.
You can use DLL injection technique to achieve this. You do it by first creating a DLL whose DLLMain, registers the Ctrl-break Handler. Then you open the target process and write the path to your DLL in its address space using VirtualAllocEx and WriteProcessMemory. Then you launch a remote thread in the target process with LoadLibrary as the entry point and the address of the DLL path as the parameter.
This causes your DLL to be loaded in the target process and DLLMain to be called which will register the CtrlHandler.
You can do all the above things only if your application has privilages to write into target process.
You may refer to this link for the sample code.
You can send the WM_KEYDOWN and WM_KEYUP events to the window handle using the sendmessage api

Reconnect to Process Started Via COM

First, I'd like to note that I need to use the COM/OLE2 APIs, the low level stuff, the stuff you can put in a C Windows Console program. I can't use MFC. I can't use .NET.
My question is:
Given the following code:
CLSID clsid;
HRESULT hr;
hr = CLSIDFromProgID(L"InternetExplorer.Application", &clsid);
assert(SUCCEEDED(hr));
hr = CoCreateInstance(clsid,
NULL,
CLSCTX_LOCAL_SERVER,
IID_IDispatch,
(void **)&(iePtr_));
assert(SUCCEEDED(hr));
Is there a way to write some information to the disk so that I can reconnect to the same instance of IE later on? Basically can "iePtr_" be stringified for later reconstitution by some other process?
Thanks.
---- added later------
The broader problem I am trying to solve is that I want to start an AutoCAD application, load some data into it, and then leave it running for my client to interact with. Later he will go back to my application and I want to reconnect to the same AutoCAD session and feed it more data.
Now, I full well realize I can keep the IDispatch pointer in memory in my application and I'll be able to continue to interact with the same AutoCAD process. That's my fallback position.
However, I use a "wrapper" program to do my COM stuff. So the wrapper is transient. My main application starts the wrapper, then the wrapper communicates, and then exits. I just want subsequent wrapper processes to be able to reconnect to the same AutoCAD process.
Why use a wrapper? Here's the working reason: My main application is a 32-bit application, but I can use a 64-bit wrapper and communicate with 64-bit AutoCAD. I need to be able to communicate with 64-bit AutoCAD and can probably not port my main application easily (500K+ lines of C++) vs. my wrapper program (couple hundred lines).
If the application registered itself in the Running Object Table, you can use the GetActiveObject function to get a reference to the application object.
IUnknown *pUnknown;
hr = GetActiveObject(clsid, NULL, &pUnknown);
assert(SUCCEEDED(hr));
hr = pUnknown->QueryInterface(IID_IDispatch, (void **)&(iePtr_));
assert(SUCCEEDED(hr));
CoMarshalInterface (and related APIs) can be used to marshal an interface into another thread, process or different PC on the network. I don't know how long you are allowed to wait before completing the marshaling process, but in principal, if the object you are marshaling an interface to has not been closed the marshaling process can be completed later.
Being able to destroy an OLE object and later restore "the same object" is tied into what are called Monikers, and if you (can) understand those then your OLE/COM Juju is powerful indeed.
I'd suggest making the wrapper layer long lived rather than transient, therefore it can easily hold a single reference to the third application.
The wrapper can still appear transient to the client code.
If you make the wrapper a COM singleton then each time you cocreate it, you will get back the same instance.
To ensure the wrapper lives for the lifetime of your client hold a reference from startup to shutdown. This reference does not need to be wired through to other code. All other code simply creates the singleton every time it wants it.
Nope, that's impossible. The whole idea of COM is that the COM server is started transparently and only preserves state until you have stopped using its objects. After you've released the COM objects the COM subsystem is free to completely stop the server and there's no way to recreate the same process. The only way a similar result would be possible is to have a COM object with serialization methods that would permit saving the state into a stream and restoring it from a stream. But even then you would have to CoCreateInstance() again, obtain a new COM object interface pointer and call the restore method of that object.
The pointer you get from CoCreateInstance is only valid for the current process, if you save it on disk and restore later it will become invalid.