Drydo's Blog

Teenager of the Internet

vbCity Blogs moved to:
http://cs.vbcity.com/blogs
  Home :: Syndication  :: Login   Community Forums   :: vbCity.com   :: DevCity.NET  

To be quite frank, after 3 months of ASP.NET development, the opportunity to do some down and dirty API programming really appealled to me today. So, the question (as indicated by the title) involved a member wanting to disable the right-click context menu from the Flash ActiveX component when being used in a WinForms application. (See previous blog entries for examples of Flash in VB.NET and communication between the two such as http://blogs.vbcity.com/drydo/archive/2005/10/18/5586.aspx).

The simple answer is to capture the right-click of the Flash Window itself and prevent it from being processed. A little play with Spy++ quickly came up with the answers and the rest was all about good old fashioned subclassing. I must admit it pinched the API declarations from Pinvoke.net and smartened them up a tad and that is pretty much it.

For the record, this is something I've been meaning to do for a while + I can leave work not feeling like some CSS floozy :)

Note: to recreate, create one form, one button and add one Flash Active X control. Copy and Paste as necessary. Tested in VS2005. If you get the dreaded 'Failed to import the ActiveX control' message, check out this workaround

Imports System.Runtime.InteropServices

Public Class Form1

#Region "API Routines"

    <DllImport("User32.dll")> _
   Private Shared Function EnumChildWindows _
       (ByVal WindowHandle As IntPtr, ByVal Callback As EnumWindowProcess, _
       ByVal lParam As IntPtr) As Boolean
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Sub GetClassName(ByVal hWnd As System.IntPtr, _
   ByVal lpClassName As System.Text.StringBuilder, ByVal nMaxCount As Integer)
    End Sub

    <DllImport("user32.dll", CharSet:=CharSet.Auto)> _
    Private Overloads Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal
nIndex As Integer, ByVal dwNewLong As Integer) As Integer End Function <DllImport("user32.dll", CharSet:=CharSet.Auto)> _ Private Overloads Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal
nIndex As Integer, ByVal dwNewLong As FlashCaptureRoutine) As Integer End Function <DllImport("user32.dll", CharSet:=CharSet.Auto)> _ Private Shared Function CallWindowProc(ByVal lpPrevWndFunc As Integer, ByVal
hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer End Function #End Region #Region "Delegates" ' Used for processing Flash Window messages Public Delegate Function FlashCaptureRoutine(ByVal hwnd As Integer, ByVal
Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer ' Used for enumerating child windows Public Delegate Function EnumWindowProcess(ByVal Handle As IntPtr, ByVal Parameter As IntPtr) As Boolean #End Region ' Constants Public Const GWL_WNDPROC As Integer = (-4) Public Const WM_ENTERMENULOOP As Integer = &H211 Public Const WM_RBUTTONDOWN As Integer = &H204 Public Const WM_INITMENU = &H116 ' Private vars Private mFlashWindowHandle As IntPtr Private mPreviousHandle As Integer Private isCapturing As Boolean Private Sub Form1_FormClosing(ByVal sender As Object, ByVal
e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing ' Cleanup if appropriate If isCapturing Then CleanupCapture() End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles MyBase.Load ' Load the test movie... Me.AxShockwaveFlash1.Movie = "MyTestMovie.swf" Me.AxShockwaveFlash1.Menu = True End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles Button1.Click ' Capture / Reset Flash Window Processing as appropriate ' React as approrpiate If isCapturing Then ' Resume CleanupCapture() Else ' Capture events CaptureRightClick() End If ' Switch over the flag isCapturing = Not isCapturing End Sub Private Sub CaptureRightClick() ' Attempt to obtain the Flash Window EnumChildWindows(Me.Handle,
AddressOf EnumWindow, IntPtr.Zero) ' Subclass using new routine storing the old result mPreviousHandle = SetWindowLong(mFlashWindowHandle, GWL_WNDPROC, AddressOf FlashWindowCapture) End Sub Private Sub CleanupCapture() ' Reset back to the original handle... SetWindowLong(mFlashWindowHandle, GWL_WNDPROC, mPreviousHandle) End Sub Private Function FlashWindowCapture(ByVal hwnd As Integer, ByVal Msg As Integer,
ByVal wParam As Integer, ByVal lParam As Integer) As Integer ' Capture the appropriate message and prevent it from being processed Select Case Msg Case WM_RBUTTONDOWN ' Exit Exit Function End Select ' Carry on... Return CallWindowProc(mPreviousHandle, hwnd, Msg, wParam, lParam) End Function Private Function EnumWindow(ByVal Handle As IntPtr, ByVal Parameter As IntPtr) As Boolean ' Obtain the class name of the child window Dim ClassName As New System.Text.StringBuilder("", 255) GetClassName(Handle, ClassName, ClassName.MaxCapacity) ' Is this the Flash Window? If ClassName.ToString = "MacromediaFlashPlayerActiveX" Then mFlashWindowHandle = Handle End If Return True End Function End Class

posted on Monday, March 03, 2008 4:42 PM

Feedback

# re: Disabling Flash (AxShockwaveFlash) Right-Click Context Menu 7/26/2009 10:05 PM Zoran
Its working alone but in combination width my code i have this error :( .

CallbackOnCollectedDelegate was detected
Message: A callback was made on a garbage collected delegate of type 'TL5novi!TL5.FlashCaptureRoutine::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.


Post Feedback

Title:
Name:
Url:
Comments: 
Protected by Clearscreen.SharpHIPEnter the code you see: