我把代码贴出来,请高手帮我分析一下。标准模块代码 Option Explicit Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long Public Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As LongPublic hWndOfPlayVideo As Long '视频播放窗口的句柄'取得Flash.ocx控件视频播放窗口的句柄 Public Function EnumFlashChildProc(ByVal lhWnd As Long, ByVal lParam As Long) As Long Dim RetVal As Long Dim WinClassBuf As String * 255 Dim WinClass As String RetVal = GetClassName(lhWnd, WinClassBuf, 255) If (InStr(WinClassBuf, Chr(0)) > 0) Then WinClass = Left(WinClassBuf, InStr(WinClassBuf, Chr(0)) - 1) End If If WinClass = "MacromediaFlashPlayerActiveX" Then hWndOfPlayVideo = lhWnd EnumChildProc = False Else If Left(WinClass, 4) = "ATL:" Then hWndOfPlayVideo = lhWnd EnumChildProc = False Else EnumChildProc = True End If End If End Function'取得DVD控件MsWebdvd.dll视频播放窗口的句柄 Public Function EnumDVDChildProc(ByVal lhWnd As Long, ByVal lParam As Long) As Long Dim RetVal As Long Dim WinClassBuf As String * 255 Dim WinClass As String RetVal = GetClassName(lhWnd, WinClassBuf, 255) Debug.Print "RetVal=" & Str(RetVal) & " WinClassBuf=" & WinClassBuf If InStr(WinClassBuf, "MSMFVideoClass") > 0 Then hWndOfPlayVideo = lhWnd GetDVDChildProcHwnd = False Else GetDVDChildProcHwnd = True End If End Function 窗体模块代码:所有变量都定义了的,这里不再定义。WndProc是我的回调函数,定义了鼠标事件(双击,右键等),在另一标准模块里。 以下代码均在播放开始后执行。PlayScreen是容纳控件的播放窗体。 lhWnd = PlayScreen.hwnd lRet = EnumChildWindows(lhWnd, AddressOf EnumFlashChildProc, lParam) If hWndOfPlayVideo <> 0 Then prevWndProc = SetWindowLong(hWndOfPlayVideo , GWL_WNDPROC, AddressOf WndProc) End If CJL = hWndOfPlayVideo 这几行代码在播放Flash动画后被执行,然后执行playcjl后面的代码,没有任何问题,画面上完全能够响应鼠标双击和右键菜单。 . . . lhWnd = PlayScreen.hwnd lRet = EnumChildWindows(lhWnd, AddressOf EnumDVDChildProc, lParam) If hWndOfPlayVideo <> 0 Then prevWndProc = SetWindowLong(hWndOfPlayVideo , GWL_WNDPROC, AddressOf WndProc) End If CJL = hWndOfPlayVideo 这几行代码在播放DVD光盘后被执行,然后执行playcjl后面的代码,这时PlayScreen播放窗体出问题了:标题栏不响应鼠标,画面上的右键菜单一个一个地遮住了画面,DVD继续播放,不能刷新。双击画面时,画面有一个最大化的动作,但PlayScreen窗体并没有最大化。我看了一下CPU使用率在60-70%,播放器几乎不能响应鼠标。偶尔能响应,但退出后程序崩溃。 . . playcjl: SetWindowLong Cjl, GWL_WNDPROC, prevWndProc . . . prevWndProc = GetWindowLong(Cjl, GWL_WNDPROC) Rtn = SetWindowLong(Cjl, GWL_WNDPROC, AddressOf WndProc) 为什么播放Flash可以,而播放DVD会出问题。
WndProc的代码有问题 我大概猜到是什么问题了,吧WndProc代码贴出来
'以下是我的回调函数WndProc,不知是哪个地方出错?但播放Flash动画没任何问题。 Public Function WndProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long '自定义窗口处理程序
On Error Resume Next If Msg = WM_LBUTTONDBLCLK Then '截获鼠标双击消息 Dim r As Long On Error Resume Next If (Player.PDFullScreen) Then r = ShowWindow(PlayScreen.Hwnd, SW_SHOWMINIMIZED)'最小化 Else r = ShowWindow(PlayScreen.Hwnd, SW_SHOWMAXIMIZED)'最大化 End If Else If Msg = WM_RBUTTONDOWN Then '弹出右键菜单 PlayScreen.PopupMenu PlayScreen.PlayMenu Else If Msg = WM_LBUTTONDOWN And LockMouseLeftClick = False Then '单击鼠标左键激活播放器 If ClickMouse Then Call SetWindowPos(Player.hwnd, HWND_TOPMOST, 0, 0, 0, 0, 3) Call ShowWindow(Player.hwnd, SW_RESTORE) ClickMouse = False Else ClickMouse = True End If Else WndProc = CallWindowProc(prevWndProc, hwnd, Msg, wParam,lParam) '操作系统预定义窗口处理程序 End If End If End If End Function
程序崩溃,危险0。。
2.程序崩溃的原因不打清楚,代码贴出来
Option Explicit
Public Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Public Declare Function EnumChildWindows Lib "user32" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long
Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As LongPublic hWndOfPlayVideo As Long '视频播放窗口的句柄'取得Flash.ocx控件视频播放窗口的句柄
Public Function EnumFlashChildProc(ByVal lhWnd As Long, ByVal lParam As Long) As Long
Dim RetVal As Long
Dim WinClassBuf As String * 255
Dim WinClass As String
RetVal = GetClassName(lhWnd, WinClassBuf, 255)
If (InStr(WinClassBuf, Chr(0)) > 0) Then
WinClass = Left(WinClassBuf, InStr(WinClassBuf, Chr(0)) - 1)
End If
If WinClass = "MacromediaFlashPlayerActiveX" Then
hWndOfPlayVideo = lhWnd
EnumChildProc = False
Else
If Left(WinClass, 4) = "ATL:" Then
hWndOfPlayVideo = lhWnd
EnumChildProc = False
Else
EnumChildProc = True
End If
End If
End Function'取得DVD控件MsWebdvd.dll视频播放窗口的句柄
Public Function EnumDVDChildProc(ByVal lhWnd As Long, ByVal lParam As Long) As Long
Dim RetVal As Long
Dim WinClassBuf As String * 255
Dim WinClass As String
RetVal = GetClassName(lhWnd, WinClassBuf, 255)
Debug.Print "RetVal=" & Str(RetVal) & " WinClassBuf=" & WinClassBuf
If InStr(WinClassBuf, "MSMFVideoClass") > 0 Then
hWndOfPlayVideo = lhWnd
GetDVDChildProcHwnd = False
Else
GetDVDChildProcHwnd = True
End If
End Function
窗体模块代码:所有变量都定义了的,这里不再定义。WndProc是我的回调函数,定义了鼠标事件(双击,右键等),在另一标准模块里。
以下代码均在播放开始后执行。PlayScreen是容纳控件的播放窗体。 lhWnd = PlayScreen.hwnd
lRet = EnumChildWindows(lhWnd, AddressOf EnumFlashChildProc, lParam)
If hWndOfPlayVideo <> 0 Then
prevWndProc = SetWindowLong(hWndOfPlayVideo , GWL_WNDPROC, AddressOf WndProc)
End If
CJL = hWndOfPlayVideo
这几行代码在播放Flash动画后被执行,然后执行playcjl后面的代码,没有任何问题,画面上完全能够响应鼠标双击和右键菜单。
.
.
.
lhWnd = PlayScreen.hwnd
lRet = EnumChildWindows(lhWnd, AddressOf EnumDVDChildProc, lParam)
If hWndOfPlayVideo <> 0 Then
prevWndProc = SetWindowLong(hWndOfPlayVideo , GWL_WNDPROC, AddressOf WndProc)
End If
CJL = hWndOfPlayVideo
这几行代码在播放DVD光盘后被执行,然后执行playcjl后面的代码,这时PlayScreen播放窗体出问题了:标题栏不响应鼠标,画面上的右键菜单一个一个地遮住了画面,DVD继续播放,不能刷新。双击画面时,画面有一个最大化的动作,但PlayScreen窗体并没有最大化。我看了一下CPU使用率在60-70%,播放器几乎不能响应鼠标。偶尔能响应,但退出后程序崩溃。
.
.
playcjl: SetWindowLong Cjl, GWL_WNDPROC, prevWndProc
.
.
.
prevWndProc = GetWindowLong(Cjl, GWL_WNDPROC)
Rtn = SetWindowLong(Cjl, GWL_WNDPROC, AddressOf WndProc)
为什么播放Flash可以,而播放DVD会出问题。
我大概猜到是什么问题了,吧WndProc代码贴出来
Public Function WndProc(ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long '自定义窗口处理程序
On Error Resume Next If Msg = WM_LBUTTONDBLCLK Then '截获鼠标双击消息
Dim r As Long
On Error Resume Next
If (Player.PDFullScreen) Then
r = ShowWindow(PlayScreen.Hwnd, SW_SHOWMINIMIZED)'最小化
Else
r = ShowWindow(PlayScreen.Hwnd, SW_SHOWMAXIMIZED)'最大化
End If
Else
If Msg = WM_RBUTTONDOWN Then '弹出右键菜单
PlayScreen.PopupMenu PlayScreen.PlayMenu
Else
If Msg = WM_LBUTTONDOWN And LockMouseLeftClick = False Then '单击鼠标左键激活播放器
If ClickMouse Then
Call SetWindowPos(Player.hwnd, HWND_TOPMOST, 0, 0, 0, 0, 3)
Call ShowWindow(Player.hwnd, SW_RESTORE)
ClickMouse = False
Else
ClickMouse = True
End If
Else
WndProc = CallWindowProc(prevWndProc, hwnd, Msg, wParam,lParam) '操作系统预定义窗口处理程序
End If
End If
End If
End Function
你 dvd的时候,播放线程(就是执行WndProc的线程)和主线程不是同一个线程,这个时候,wndproc是不能访问主界面的控件的,一访问就会出错,我猜测是这样解决的办法是你要控制的控件,就是那个菜单,可能要在wndproc内创建
因为flash播放只是用你程序本身的线程,没有用多线程,但是dvd就不同了
其实,利用HOOK技术可顺利解决。
编写一个全局的鼠标钩子,然后:1、将鼠标事件限定在DVD视频范围内;2、窗体移动时响应鼠标的区域随之变动;3、窗体和DVD控件同时最大化。
所有问题全解决了,简直太爽了!
解决了此问题,也解决了我长期以来的一个误区:以前我总认为控件最大化后,窗体一定是最大化。现在我明白了,控件最大化,窗口不一定最大化。窗口最小化,控件也可以最大化。
高手都劝我换控件,我不想换。毕竟我太喜欢DVD控件MSWebDVD.dll(Windows2000以上的操作系统自带,在system32下面),因为MSWebDVD可以在VB里轻松搞定DVD“字幕”、“音频”和“区码”、“角度”等等。