Shellexecute


KenO

Recommended Posts

Hello,

I am aware that the ability within DAQFactory to call an external program, such as note pad or internet explorer, however I am wondering if there is a way to read in from task manager or another way, if the program is already running?

An example:

I have a button that allows a user to open internet explorer, and it pops up via System.ShellExecute.

If they press the button again I do not want another instance of it to open. I could set a flag saying it is already open, but if they close it via normal windows functionality ( the "x" ) I wouldn't know it was closed.

Is this possible?

Link to comment
Share on other sites

It is, but its quite tricky. Not because of DAQFactory but because its just tricky in Windows. The only way to tell if another app is running is to determine the name of its window and ask Windows if that window exists. Alas, the window name is not going to be what you expect. It probably is something like IExploreMainDlgClass or something like that. Actually, that's probably the className. You need a program like Spy++ (comes with Visual Studio) or similar to figure it out. Then you use the ::FindWindow() function to see if it exists. FindWindow() is a function in one of the Windows DLL's. You'd have to look on MSDN to see which library its in. Actually, here's the link: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633499(v=vs.85).aspx, at least for today. It looks like its in User32.dll. Then use extern() to pull the function in. The rest will take a little experimentation. Basically if that function returns 0, there are no windows open. If it returns anything else, there is.

Link to comment
Share on other sites

Thank you for your reply and of course after I thought I searched all I could in the forums before asking the question, I had found a similar question asked and answered.

http://www.azeotech.com/board/index.php?/topic/4980-windows-process-detection/page__hl__process ( mostly putting this here for the next searcher on the subject ).

I am assuming your reply with :

" HWND hWnd = ::FindWindow("windowName", NULL); " is as an MFC programmer and not within DF?

My attempts so far seem to be failing in properly declaring the prototype and pulling the function in, or improperly using the extern function, which is a new to me.

I seem to be running into the same issue as post 5 in the link, and tried to declare it as a long for the return value

Link to comment
Share on other sites

Here's the working prototype:

extern("user32.dll", "long FindWindowA(string, long)", "FindWin", "stdcall")

In actual fact, "FindWindow" doesn't exist in the library. Instead there are two others, FindWindowA and FindWindowW for the two different types of string representations. Since DAQFactory is not unicode, you have to use the ANSI version ("A").

I used a long as the second parameter because I want to pass 0 to it always. Also, since the function expects a const string pointer (the "C" in LPCTSTR), we don't have to make the string a pointer, so no [256]. We could do [256] and it would still work, but you wouldn't be able to do (my prototype):

FindWin("myWin",0)

you'd have to do (string[256], string[256]):

private string win = "myWin"

FindWin(@win, NULL)

Link to comment
Share on other sites

BTW: the return value is either 0 for not found, or a handle to the window (HWND). If you get a valid handle, you can use it for other functions, for example ::PostMessage() which would allow you to send the program a message, like WM_CLOSE, which would close the app. Note of course that its really ::PostMessageA. You'll have to search MSDN for the actual message numbers (WM_CLOSE is 0x10). The symbol, "WM_CLOSE" is defined in a header somewhere and not available in DAQFactory.

Link to comment
Share on other sites

As always thank you :)

Using Spy++ ( v.8 ) and FindWindowA(string, long) yeilded results. When searching for a "known" string I was assumingly receiving the handle ( value other than "0" ), when I would close the window and run the script again my returned value was "0", repeated over a number of times and always when the window was open a value over zero occured, and always zero when closed :)

My frustration has ended, and progress can continue!

I think this has opened a whole new level of capability for me, and I thank you!

Link to comment
Share on other sites

What value are you using in the first argument? I used partial and full executable names as shown in SysInternals Process Explorer (task manager replacement), with and without the ".exe", and partial and full window titles, but never get anything back but 0.

I also tried including the full path in the dll filename, but that didn't seem to help either.

The extern() command doesn't throw any errors, and I know it executes because when I type "FindWin(" I get a popup prototype like an internal function, so it seems to have successfully imported the function, but I never get any return other than 0.

Link to comment
Share on other sites

You have to use the window class name, which as far as I know is not available from Task Manager. I use Spy++ included with visual studio. For example, Chrome's window class is "Chrome_WidgetWin_1". DAQFactory itself doesn't have an exposed window class name.

Link to comment
Share on other sites

Ok so Closing the window is easy, fumbling a bit with the min and max as it looks like I will need to make the size,as the WM_SIZE doesn't seem to be working.

Global handy =0 // window value

extern("user32.dll", "long FindWindowA(string, long)", "FindWin", "stdcall")

handy = FindWin("IEFrame",0)

The above simple gets the value of the process ( thank you spy++ and the help here ) and stores it so I can use it later.

Then we setup the PostMessageA for use later

extern("user32.dll", "long PostMessageA(long, long)", "closebb", "stdcall") // closebb is bad browser

closebb(handy,16) //send 10 hex to the window

Link to comment
Share on other sites

You are lucky you didn't crash DAQFactory. That's the wrong prototype. There are four parameters. "Optional" parameters are not supported by DLL's. Not passing them will likely destroy your stack. The proper prototype is:

extern("user32.dll", "long PostMessageA(long, long, ulong, long)", "postMessage", "stdcall")

BTW: a useful link for those windows redefined data types: http://msdn.microsoft.com/en-us/library/aa383751%28VS.85%29.aspx

You might also consider sticking in hex and using 0x10 instead of 16.

For minimize, you'd have to do:

postMessage(handy, 0x05, 0x01, 0)

Link to comment
Share on other sites

"Optional" parameters are not supported by DLL's. Not passing them will likely destroy your stack.

extern("user32.dll", "long PostMessageA(long, long, ulong, long)", "postMessage", "stdcall")

I had read somewhere ( obviously wrongly ) the "optionals" unused could be ignored.

This might explain why my minimize/maximize was not working, as I had exactly what you did not including the 0 at the end. closebb(handy,5,1)

Looking forward to confirming this when I get back to the home office.

Cheers

Link to comment
Share on other sites

I think they meant you could put any value there, not that you couldn't provide something. The difference has to do with how parameters are passed in C. If you provide 4 parameters and the function expects 4, but 2 are "optional" the way I think they meant, the function simply ignores the values. However, if you provide 2 parameters because you think "optional" means you don't provide them, the receiving function still thinks there are 4, so pops two extra values off the stack. Now your stack is misaligned because you popped the wrong things off the stack, possibly even the return pointer. This is, of course, a watered down version of how it works, but close enough.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.