你别笑我菜,我也很无奈! (10分)

  • 主题发起人 风雨燕归来
  • 开始时间

风雨燕归来

Unregistered / Unconfirmed
GUEST, unregistred user!
有关VB的问题,我知道这里全是高手,所以就放在这里了,帮帮忙.
在某窗体中有如下操作:
Me.WindowState = 1
Me.Hide
On Error GoTo fff
pid = Shell("j2sell.exe", vbNormalFocus)
phnd = OpenProcess(&H100000, 0, pid)
If phnd <> 0 then
WaitForSingleObject phnd, &amp;HFFFFFFFF
CloseHandle phnd
End If
Me.Show
Me.WindowState = 0
上面可以通过phnd创建一个进程一直等到j2sell执行完毕再执行下面的代码,但是我必须使用shellexecute API函数,而不是shell,该怎么实现.
说到底就是如何检测一个程序是否在执行的问题,如果是,则等待,否则继续.
 
shellexecute API返回的是个什么东东,如何通过它得到 进程ID.
 
如果能直接得到进程句柄就更好了.
 
如果用shellexecuteEx也行,但是不能返回进程句柄,苦恼中.
[:D]
 
一个Windows API函数,返回一个实例柄。
HINSTANCE ShellExecute(
HWND hwnd, // handle to parent window
LPCTSTR lpOperation, // pointer to string that specifies operation to perform
LPCTSTR lpFile, // pointer to filename or folder name string
LPCTSTR lpParameters, // pointer to string that specifies executable-file parameters
LPCTSTR lpDirectory, // pointer to string that specifies default directory
INT nShowCmd // whether file is shown when opened
);
 
he WaitForSingleObject function returns when one of the following occurs:
?The specified object is in the signaled state.
?The time-out interval elapses.

DWORD WaitForSingleObject(
HANDLE hHandle, // handle of object to wait for
DWORD dwMilliseconds // time-out interval in milliseconds
);

Parameters
hHandle
Identifies the object. For a list of the object types whose handles can be specified, see the following Remarks section.
Windows NT: The handle must have SYNCHRONIZE access. For more information, see
Access Masks and Access Rights.
dwMilliseconds
Specifies the time-out interval, in milliseconds. The function returns if the interval elapses, even if the object's state is nonsignaled. If dwMilliseconds is zero, the function tests the object's state and returns immediately. If dwMilliseconds is INFINITE, the function's time-out interval never elapses.

Return Values
If the function succeeds, the return value indicates the event that caused the function to return.
If the function fails, the return value is WAIT_FAILED. To get extended error information, call
GetLastError.
The return value on success is one of the following values:
Value Meaning
WAIT_ABANDONED The specified object is a mutex object that was not released by the thread that owned the mutex object before the owning thread terminated. Ownership of the mutex object is granted to the calling thread, and the mutex is set to nonsignaled.
WAIT_OBJECT_0 The state of the specified object is signaled.
WAIT_TIMEOUT The time-out interval elapsed, and the object's state is nonsignaled.

Remarks
The WaitForSingleObject function checks the current state of the specified object. If the object's state is nonsignaled, the calling thread enters an efficient wait state. The thread consumes very little processor time while waiting for the object state to become signaled or the time-out interval to elapse.
Before returning, a wait function modifies the state of some types of synchronization objects. Modification occurs only for the object or objects whose signaled state caused the function to return. For example, the count of a semaphore object is decreased by one.
The WaitForSingleObject function can wait for the following objects:
Object Description
Change notification The FindFirstChangeNotification function returns the handle. A change notification object's state is signaled when a specified type of change occurs within a specified directory or directory tree.
Console input The handle is returned by the CreateFile function when the CONIN$ value is specified, or by the GetStdHandle function. The object's state is signaled when there is unread input in the console's input buffer, and it is nonsignaled when the input buffer is empty.
Event The CreateEvent or OpenEvent function returns the handle. An event object's state is set explicitly to signaled by the SetEvent or PulseEvent function. A manual-reset event object's state must be reset explicitly to nonsignaled by the ResetEvent function. For an auto-reset event object, the wait function resets the object's state to nonsignaled before returning. Event objects are also used in overlapped operations, in which the state is set by the system.
Mutex The CreateMutex or OpenMutex function returns the handle. A mutex object's state is signaled when it is not owned by any thread. The wait function requests ownership of the mutex for the calling thread, changing the mutex's state to nonsignaled when ownership is granted.
Process The CreateProcess or OpenProcess function returns the handle. A process object's state is signaled when the process terminates.
Semaphore The CreateSemaphore or OpenSemaphore function returns the handle. A semaphore object maintains a count between zero and some maximum value. Its state is signaled when its count is greater than zero and nonsignaled when its count is zero. If the current state is signaled, the wait function decreases the count by one.
Thread The CreateProcess, CreateThread, or CreateRemoteThread function returns the handle. A thread object's state is signaled when the thread terminates.
Timer The CreateWaitableTimer or OpenWaitableTimer function returns the handle. Activate the timer by calling the SetWaitableTimer function. The state of an active timer is signaled when it reaches its due time. You can deactivate the timer by calling the CancelWaitableTimer function. The state of an active timer is signaled when it reaches its due time. You can deactivate the timer by calling the CancelWaitableTimer function.

In some circumstances, you can specify a handle of a file, named pipe, or communications device as a synchronization object in lpHandles. However, their use for this purpose is discouraged.
You have to be careful when using the wait functions and DDE. If a thread creates any windows, it must process messages. DDE sends messages to all windows in the system. If you have a thread that uses a wait function with no time-out interval, the system will deadlock. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForSingleObject.
 
VB我很久没有用过了。我给你说一个在Delphi中的方法。
1、用Findwindow函数查找窗口的标题。可以得到该窗口是否打开。
 
这个东西更不行的,因为压根没有进程句柄,用它还可以
Public Type SHELLEXECUTEINFO
cbSize As Long
fMask As Long
hwnd As Long
lpVerb As String
lpFile As String
lpParameters As String
lpDirectory As String
nShow As Long
hInstApp As Long
' Optional fields
lpIDList As Long
lpClass As String
hkeyClass As Long
dwHotKey As Long
hIcon As Long
hProcess As Long
End Type
Public Declare Function ShellExecuteEX Lib "shell32.dll" Alias "ShellExecuteEx" (SEI As SHELLEXECUTEINFO) As Long
但每次返回的进程句柄hProcess都是零,怎么办呀?
 
下面我简单地介绍一下FindWindow()函数的用法。要使用该API,请先建立一个.bas模块,然后从winapi/win32api.txt中拷贝如下的FindWindow()函数的声明:
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
这个函数有两个参数,第一个是要找的窗口的类,第二个是要找的窗口的标题。在搜索的时候不一定两者都知道,但至少要知道其中的一个。有的窗口的标题是比较容易得到的,如"计算器",所以搜索时应使用标题进行搜索。但有的软件的标题不是固定的,如"记事本",如果打开的文件不同,窗口标题也不同,这时使用窗口类搜索就比较方便。如果找到了满足条件的窗口,这个函数返回该窗口的句柄,否则返回0。
前面提到的VB的FindWindow()函数的声明将两个参数都定义为String类型,而在实际使用过程中,如果我们忽略某个参数就将该参数的定义又As String改为As Any。这里的As Any相当于C语言中的强制类型转换。例如,如果我们忽略窗口的类,就将定义修改如下:
Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As String) As Long
然后,在调用时使用如下语句:
hwndCalc = FindWindow(0&amp;, "计算器")
这里的0&amp;就表示忽略类名。需要注意的是FindWindow(0&amp;, "计算器")和FindWindow("", "计算器")有两种完全不同的含义,前者表示忽略窗口的类,而后者表示窗口的类是个空串。类似的,我们也可以忽略标题而搜索指定的类。
从上面的讨论中可以看出,如果要搜索的外部程序的窗口标题比较容易得到,问题是比较简单的。可如果窗口的标题不固定或者根本就没有标题,怎么得到窗口的类呢?如果你安装了Visual C++,你可以使用其中的Spy++(如果没有VC++,在VB的盘上也可以找到Spy),在Spy++中有一个FindWindow工具,它允许你使用鼠标选择窗口,然后Spy++会显示这个窗口的类。
在Win32 API中还有一个FindWindowEx,它非常适合寻找子窗口。
 
to humanc2d4:
这是原程序:
Me.WindowState = 1
Me.Hide
On Error GoTo fff
ShellExecute 0, "open", "D:/Documents and Settings/Administrator/桌面/供应软件/供应管理.adp", "", "", 3
WinHandle = FindWindow(0&amp;, "供应管理--照东方纸业集团有限公司")
If WinHandle = 0 then
MsgBox "1"
GetWindowThreadProcessId WinHandle, ProcessID
If ProcessID = 0 then
GoTo fff
ProcessHandle = OpenProcess(&amp;H100000, 0, ProcessID)
If ProcessHandle <> 0 then
WaitForSingleObject ProcessHandle, &amp;HFFFFFFFF
CloseHandle ProcessHandle
End If

Me.Show
Me.WindowState = 0
我一开始就想这么干的,可我findwindows的时候,新的程序还没有打开呢,叫我怎么找窗口呢?
 
to wlmmlw:
兄弟,你跟我写E文,就跟对牛弹琴一般,有没有简单一点的?
 
你可以用一个TIMER控件。一直查找,直到找到该窗口。找到后再开始获取信息,当findwindow返回为空时表名该窗口已关闭。然后再执行其他代码。
 
to :humanc2d4
关键是流程是这样的,
打我执行这段过程的时候,首先是让当前窗口最小化,然后调用一个外部程序,然后程序一直等待,直到这个外部程序执行完毕,再让原先最小化的窗口复原.
我若要用timer控件找窗口,首先当前进程不能暂停,第二,窗口先是找不着,然后是找着了,最后又是找不着了,中我怎么检测呢?
 
“窗口先是找不着,然后是找着了,最后又是找不着了”
这个很容易呀,我不知道你怎么认为这个很复杂吗?
*****************************************
1、TIMER控件
2、设一个Boolean全局变量为T
3、在按钮中写事件调用EXE,然后启动TIMER
4、在TIMER控件中写
if (T=true) and (findwindow(...)=null) then

执行代码;
if findwindow(...)<>null then

t:=true;

 
楼上你好:你说的方法或许能解决问题,但我前面都用的是ShellExecuteEX
想想为什么它返回的lprocess总是为零.只要我能得到外接程序的进程句柄,一切都解决了.
 
你自己创建一个进程,而且要返回其进程句柄,为何不用 CreateProcess 呢,返回信息
非常详细啊。
 
因为很久没有动VB了,只好提供给你Delphi的代码了,这个不是俺写的,不过可以用。
其实使用ShellExecute不好,最好使用CreateProcess

{****************************************}
{17、执行其他可执行程序,等待它执行完毕再继续执行自己,否则阻塞}
{****************************************}
function TFrm1.ExecAndWait(const Filename, Params: string;
WindowState: word): boolean;
var SUInfo: TStartupInfo;
ProcInfo: TProcessInformation;
CmdLine: string;
begin
CmdLine := '"' + Filename + '"' + Params;
{ 注意检查长文件名}
FillChar(SUInfo, SizeOf(SUInfo), #0);
with SUInfodo
begin
cb := SizeOf(SUInfo);
dwFlags := STARTF_USESHOWWINDOW;
wShowWindow := WindowState;
end;

Result := CreateProcess(NIL, PChar(CmdLine), NIL, NIL,
FALSE,CREATE_NEW_CONSOLE or NORMAL_PRIORITY_CLASS, NIL,
PChar(ExtractFilePath(Filename)), SUInfo, ProcInfo);
if Result then
{等待结束 }
begin
WaitForSingleObject(ProcInfo.hProcess, INFINITE);
CloseHandle(ProcInfo.hProcess);
{清理句柄 }
CloseHandle(ProcInfo.hThread);
end;
end;
 
给你个标准的方法。
procedure TForm1.Button1Click(Sender: TObject);
var
proc_info: TProcessInformation;
startinfo: TStartupInfo;
success:boolean;
begin
FillChar(proc_info, sizeof(TProcessInformation), 0);
FillChar(startinfo, sizeof(TStartupInfo), 0);
startinfo.cb := sizeof(TStartupInfo);
success:= CreateProcess(nil,'D:/project1.EXE', nil,nil, false, NORMAL_PRIORITY_CLASS, nil, nil,startinfo, proc_info);
if success then
begin
WaitForSingleObject(proc_info.hProcess, INFINITE);
CloseHandle(proc_info.hProcess);
Application.MessageBox(程序执行完毕'','Info', MB_ICONINFORMATION);
end
else
begin
Application.MessageBox('不能执行程序 '+ 'application', 'Error', MB_ICONEXCLAMATION);
end;

end;
 
或者是:
1、函数
function WinExecAndWait32(FileName:String;
Visibility :integer):integer;
var
zAppName:array[0..512] of char;
zCurDir:array[0..255] of char;
WorkDir:String;
StartupInfo:TStartupInfo;
ProcessInfo:TProcessInformation;
begin
StrPCopy(zAppName,FileName);
GetDir(0,WorkDir);
StrPCopy(zCurDir,WorkDir);
FillChar(StartupInfo,Sizeof(StartupInfo),#0);
StartupInfo.cb := Sizeof(StartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow := Visibility;
if not CreateProcess(nil,
zAppName, { pointer to command line string }
nil, { pointer to process security attributes }
nil, { pointer to thread security attributes }
false, { handle inheritance flag }
CREATE_NEW_CONSOLE or { creation flags }
NORMAL_PRIORITY_CLASS,
nil, { pointer to new environment block }
nil, { pointer to current directory name }
StartupInfo, { pointer to STARTUPINFO }
ProcessInfo) then
Result := -1 { pointer to PROCESS_INF }
else
begin
WaitforSingleObject(ProcessInfo.hProcess,INFINITE);
end;
end;

2、调用
WinExecAndWait32('d:/project1.exe',1);
showmessage('1');
 
楼上你们说的都对,关键问题是:我要调用的外部程序是ADP文件,打开方式是用Access打开的,而不是EXE文件,所以行不通.请大家再发表意见.
 
顶部