Get PID from ShellExecute - c++

I am launching a process from ShellExecuteEx, and I really need to get the ProcessID (It's part of the requirement of this class).
Somehow all the important SHELLEXECUTEINFO returns null.
So for example if I use this code:
exInfo.lpVerb = "open";
exInfo.lpFile = "C:\\Windows\\system32\\cmd.exe";
exInfo.nShow = 5;
ShellExecuteExA(exInfo);
It launched CMD.exe. But now I need to get it's PID.
exInfo.hwnd is returning 0, and exInfo.hProcess is returning null.
Is this normal behaviour?
I don't really want to resort to using CreateProcess(), because my function should also be able to launch documents like "C:\doc1.docx". This is just a method, in which I cannot predict what is going to be launched (So I cannot know the window title/classname from beforehand, get the hWnd from there and then get the PID).
Could somebody kindly point out my mistake? Thanks.

You need to set a flag (SEE_MASK_NOCLOSEPROCESS) in exInfo.fMask

Related

Setting global environment variables programmatically

I need to set an environment variable programmatically.
Microsoft provides documentation for that here. You just need to create a new value in the registry under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment. This part works fine.
The problem is that these changes only come into effect after logging out and logging in again.
To circument this they propose to execute this little piece of code:
if (!SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
(LPARAM) "Environment", SMTO_ABORTIFHUNG,
5000, &dwReturnValue))
{
... take action in case of failure
}
I did exactly this, SendMessageTimeout returns TRUE, but at least under Windows 10 it has no effect. A newly opened command prompt window still won't show the newly created variable.
I also tried to run this piece of code in an elevated process, but the result is still the same.
But when I use system applet for changing environment variables, my newly created variable shows up and when I click OK on the applet and when I open another command prompt, then the variable is there.
Any thoughts?
The problem was solved by calling explicitly the wide version of SendMessageTimeout and sending the "Environment" as wide string:
SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
(LPARAM)L"Environment", SMTO_ABORTIFHUNG, 5000, &dwReturnValue);
As Michael found out, the string width needs to match the A/W function type. WM_SETTINGCHANGE is in the < WM_USER range and will be marshaled by the window manager.
You can use the TEXT macro to create code that works for everyone everywhere if you don't want to hardcode the function name suffix:
SendMessageTimeout(
HWND_BROADCAST,
WM_SETTINGCHANGE,
0,
(LPARAM) TEXT("Environment"),
SMTO_ABORTIFHUNG,
5000,
&dwReturnValue
);

What is the best way to keep a ATL service running

I have created a ATL service and while testing I simply kept it running by leaving a while loop that ran forever (see code below)
HRESULT Run(_In_ int nShowCmd = SW_HIDE)
{
m_running = true;
HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, &MyFunctionToRunInTheService, 0, 0, 0);
while(m_running);
return CAtlServiceModuleT::Run(nShowCmd);
}
Im now ready to actually run it as a real service but am not sure how I go about doing this? I have looked all over the next and dont seem to be able to find one example of a ATL service.
If I remove the thread code and call the method direct the service is constantly in a start status. If i remove the loop the service simply starts and stops straight away. Any sugestions?
Ive fixed the problem by changing the code to
HRESULT Run(_In_ int nShowCmd = SW_HIDE)
{
_beginthreadex(NULL, 0, &CheckForExpiredFiles, 0, 0, 0);
return CAtlServiceModuleT::Run(nShowCmd);
}
I didnt really need the while loop at all. On further investigation the code to keep the service alive comes as standard. The problem was that the PreMessageLoop method in atlbase.h was returning S_FALSE which casued the service to stop. The reason it returned S_FALSE in my case was becuase I had not added any COM objects. I have therefore overridden the PreMessageLoop method to return S_OK in this case.
Well, in my case, add _ATL_NO_COM_SUPPORT macro to C\C++ preprocessor solve the problem.
See more here...

another win32 problem

Having a problem here with creating a child window with c++ and win32 api.
If i check the getLastError function its returning "87" but i dont know what that means.
For what i know my code does not contain errors, can someone take a look at my code and help me figure out whats wrong with it.
(This is in the WinProc WM_CREATE section.)
HWND hChildWindow = CreateWindowEx(WS_EX_CLIENTEDGE,0,NULL,WS_OVERLAPPEDWINDOW|WS_VISIBLE,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,hwnd,0,GetModuleHandle(0),NULL);
if(!hChildWindow)
{
char text[256];
int errormsg = (int)GetLastError();
sprintf(text,"Error# %i",errormsg);
MessageBox(0,text,"Error",MB_OK|MB_ICONEXCLAMATION);
return false;
}
87 = Invalid Parameter - be aware that you can use FormatMessage to get a string message from an error code.
The 2nd parameter to CreateWindowEx is a window class (either string or ATOM). Obviously NULL is not a valid value.
P.S.
For what i know my code does not
contain errors...
Beware of such a loud phrases. When something doesn't work everything should be checked carefully. Otherwise you may just accuse something/someone without any good for solving the problem. Check everything vs standard/documentation/specifications/etc. before you make any judgement.
A quick look through the System Error Codes reference indicates ERROR_INVALID_PARAMETER. You're most likely passing in an invalid combination of styles/flags to your window.

"Debug Assertion" Runtime Error on VS2008?

I'm writing a C++ MFC program on VS2008 and I'm getting this "Debug Assertion Error" when I first run the program sometimes. When I try to debug it, it takes me to this winhand.cpp file which is not part of the program I wrote so I'm not sure how to debug this.
It takes the error to this place in winhand.cpp
CObject* pTemp = LookupTemporary(h);
if (pTemp != NULL)
{
// temporary objects must have correct handle values
HANDLE* ph = (HANDLE*)((BYTE*)pTemp + m_nOffset); // after CObject
ASSERT(ph[0] == h || ph[0] == NULL);
if (m_nHandles == 2)
ASSERT(ph[1] == h);
}
So why does this error happen? Why does it only happen sometimes (50% of the time)? How would I debug this?
I'll provide some code if is needed.
THANKS!
The code that is asserting is part of MFC's CHandleMap class. MFC deals with windows as CWnd objects, but Windows deals with them as HWND handles. the handle map allows MFC to 'convert' an HWND into a pointer to the MFC object representing that object.
What the assertion seems to be doing is checking that when a lookup of the handle finds an MFC object, that the MFC object also thinks it's wrapping the same handle.
If they're different, then you get the assertion.
So it would appear that something is corrupting the handle map or the MFC object for that handle or you're doing something incorrect that gets these 2 data structures out of sync.
Some things you might do to try to debug the problem is to determine:
what MFC object is being found in the lookup (that's what's being pointed to by pObject)
what the MFC object thinks it's wrapping (that's the handle ph[0] and/or ph[1] - I'm not sure why there can be 2 of them)
what the handle is for (that's h)
Do the handles look like handle values or do they look like garbage? Does pObject point to something that looks like an MFC object, or garbage? Do any of these these things seem related?
The answers to these questions may point to what you need to do next (maybe set a debug write breakpoint on the item that looks like it's trashed).
I got this same assertion few days ago, and after some google search,
I found the solution for my case here:
http://forums.codeguru.com/showthread.php?216770-What-would-cause-this-assertion
In my case, change to misused
CDC* dc = GetDC();
CSize spaceSize = dc->GetTextExtent(" ");
dc->DeleteDC();
to
CDC* dc = GetDC();
CSize spaceSize = dc->GetTextExtent(" ");
ReleaseDC(dc);
would fix it.
Look out for code along those lines (from memory from Stroustrup's book):
c1 = (t2+t3).c_str();
(in spirit, could be other commands and expressions of course).Temporary objects are destroyed after their enclosing full expression has been evaluated, or at least the standard allows them to be. That means that what you would like to allocate to c1 may, or may not, still be in memory where it can be assigned to c1. The compiler may alert you to this issue, and the issue may or may not arise depending on what exactly you assign and other circumstances (I am not compiler writer), which would also explain why you get this error message only sometimes.
So in your shoes, I'd scan my code for similar expressions and clean them up.
When the debugger breaks, head up the call stack to the first bit of your code (if there is any - hopefully there is!). Ideally it's as simple as something in your code calling a library function incorrectly, and the library is catching the error with an assert and alerting you to that. (I don't think anyone will be able to tell what's wrong from the library code, we need to see your code.)
Otherwise, you're in for some tricky debugging: you're doing something wrong with the library that is asserting (looks like MFC) so go back and review all your MFC code and make sure everything is correct and according to the documentation.
This looks suspiciously like an error I had this morning. Is this happening in OnIdle()?
I know this is a very old post, but hoping that someone may get a little help from my answer.
I also faced a similar issue recently because of my simple mistake, then I came across this post and got a hint from "pac"'s post.
What I found is that if I use DeleteDC() to release DC returned from GetWindowDC() or GetDC() I will get the above assertion in MFC frame once CPaintDC object instance goes out of scope.
CDC * pDC = GetWindowDC();
...
ReleaseDC(pDC);
You have to use DeleteDC() only in conjunction with CreateDC() API.
CDC * pDC = new CDC();
pDC->CreateDC();
....
pDC->DeleteDC();
We had this problem when some of our project dlls were linking MFC as static library and some as shared library (check "Use of MFC" in Project settings)

how do i make this so everything can use it? C++

im somewhat new to c++ so i don't know how to do this but my main point in recoding this is to incress the speed of my program, i have been coding a project
and my code is:
HWND hWnd = FindWindow(NULL, L"*window's name*");
DWORD th32ProcId;
HANDLE hProc;
GetWindowThreadProcessId(hWnd, &th32ProcId);
hProc = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, 0, th32ProcId);
so i have about 20 functions that all use that at the start of each time i run them and the value will never change so is there some way i can declare and then set it at the value of what it finds?
my code is set up like this
one main file int main() and it's just set on a loop and it keeps retesting and calls the other functions and everything else is in a void name() and i have 2 int name()
im using VC++ 2008.
edit
no :| i just want a way i can share thoses values with all of the program.
If I understand your question correctly you want to implement some kind of caching. That would be fine and you can create a cahe with an std::map.
You would probably have something like:
std::map<std::string, HANDLE> cacheMap;
You can then check the cacheMap to see if a result exists. It if does exist you don't need to call the function, if it does not exist you would then call the function and add the result to your map.