Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / July 2007

Tip: Looking for answers? Try searching our database.

DSO Framer event not firing:  axFramerControl1_PreviewKeyDown

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Brian - 25 Mar 2007 13:56 GMT
Hi!

We are using DSOFramer to host MS Word within our WinForm-based smart client
app.

Anywhere in our app, pressing F1 raises our context-sensitive help dialog.
When our users are inside MS Word within our app and press F1, we bring up a
Help dialog that explains what they should be typing in within that segment
of the Word document.  And we give a link to open up Word's Help, if that's
what they want.

However, as we have it implemented now, there's a race condition.  Sometimes
it works perfect.  Sometimes, the MS Word process gets the F1 before we can
take it... at which point Word's help opens up immediately (simultaneously
with our dialog).

We've tried to fix this by using the following event handler exposed by
DSOFramer:

     private void axFramerControl1_PreviewKeyDown(object sender,
PreviewKeyDownEventArgs e)
       {
           if (e.KeyData == Keys.F1)
               e.IsInputKey = false;
       }

However, after hooking it up, we can never get it to step into.  We don't
think its ever getting fired.

Has anyone been able to use this event handler successfully?

Any suggestions on how to intercept the F1 key consistently?

Thanks,

Brian
Walter Wang [MSFT] - 26 Mar 2007 06:27 GMT
Hi Brian,

Word still runs in its own process even you're hosting the ole document in
your WinForm (you can observe the WinWord.exe process in task manager).
Therefore, it's difficult for WinForm's PreviewKeyDown to intercept the F1
key from seeing by WinWord. We will need a low level keyboard hook in your
process to intercept the key.

#SetWindowsHookEx Function ()
http://msdn2.microsoft.com/en-us/library/ms644990.aspx

I've created following class to do hook the keyboard:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Windows.Forms;

namespace WindowsApplication1
{
   class KeyboardHook : IDisposable
   {
       private const int WH_KEYBOARD_LL = 13;
       private const int WM_KEYDOWN = 0x0100;
       private IntPtr _hookID = IntPtr.Zero;

       public event KeyEventHandler KeyDown;

       public KeyboardHook()
       {
           _hookID = SetHook(new LowLevelKeyboardProc(HookCallback));
       }

       #region IDisposable Members

       public void Dispose()
       {
           UnhookWindowsHookEx(_hookID);
       }

       #endregion

       private IntPtr SetHook(LowLevelKeyboardProc proc)
       {
           using (Process curProcess = Process.GetCurrentProcess())
           using (ProcessModule curModule = curProcess.MainModule)
           {
               return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                   GetModuleHandle(curModule.ModuleName), 0);
           }
       }

       private delegate IntPtr LowLevelKeyboardProc(
           int nCode, IntPtr wParam, IntPtr lParam);

       private IntPtr HookCallback(
           int nCode, IntPtr wParam, IntPtr lParam)
       {
           if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
           {
               int vkCode = Marshal.ReadInt32(lParam);
               Keys key = (Keys)vkCode;
               if (KeyDown != null)
               {
                   KeyEventArgs args = new KeyEventArgs(key);
                   KeyDown(this, args);
                   if (args.Handled)
                   {
                       return new IntPtr(1);   // indicate processed
                   }
               }
           }
           return CallNextHookEx(_hookID, nCode, wParam, lParam);
       }

       [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError =
true)]
       private static extern IntPtr SetWindowsHookEx(int idHook,
           LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

       [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError =
true)]
       [return: MarshalAs(UnmanagedType.Bool)]
       private static extern bool UnhookWindowsHookEx(IntPtr hhk);

       [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError =
true)]
       private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
           IntPtr wParam, IntPtr lParam);

       [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError =
true)]
       private static extern IntPtr GetModuleHandle(string lpModuleName);
   }
}

To install the hook, modify your Program.cs as:

   static class Program
   {
       public static KeyboardHook kh;

       [STAThread]
       static void Main()
       {
           Application.EnableVisualStyles();
           Application.SetCompatibleTextRenderingDefault(false);
           using (kh = new KeyboardHook())
           {
               Application.Run(new Form1());
           }
       }
   }

The class KeyboardHook will raise an event KeyDown whenever a key is
intercepted, however, according to documentation:

#LowLevelKeyboardProc Function ()
http://msdn2.microsoft.com/en-us/library/ms644985.aspx

It's recommended not to cause too much delay when handling the hook
message; and I understand you're probably using a modal dialog when the F1
is pressed, therefore I suggest use a timer to delay the showing of the
modal dialog:

   public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();

           Program.kh.KeyDown += new KeyEventHandler(kh_KeyDown);
       }

       private bool fInCall = false;
       private Timer tmrDelayedCall;

       void kh_KeyDown(object sender, KeyEventArgs e)
       {
           if (e.KeyCode == Keys.F1 && !fInCall)
           {
               e.Handled = true;
               fInCall = true;
               tmrDelayedCall = new Timer();
               tmrDelayedCall.Interval = 1;
               tmrDelayedCall.Tick += new
EventHandler(tmrDelayedCall_Tick);
               tmrDelayedCall.Start();
           }
       }

       void tmrDelayedCall_Tick(object sender, EventArgs e)
       {
           tmrDelayedCall.Stop();
           MessageBox.Show("F1");
           fInCall = false;
       }
   }

Intercepting all keys in the hook and raise events for them may not be
necessary if you only need to intercept the F1 key, you can check the key
in the hook and raise event accordingly.

Please try this and let me know the result on your side. Thanks.

Sincerely,
Walter Wang (wawang@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications. If you are using Outlook Express, please make sure you clear the
check box "Tools/Options/Read: Get 300 headers at a time" to see your reply
promptly.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
Walter Wang [MSFT] - 28 Mar 2007 11:25 GMT
Hi Brian,

Have you seen my last reply? What do you think of the suggestion?

Regards,
Walter Wang (wawang@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
Brian - 03 Apr 2007 20:49 GMT
> Hi Brian,
>
> Have you seen my last reply? What do you think of the suggestion?

Yes, Walter... I thought I responded to your note with a big thank you...
but I guess it didn't go out... sorry.

We will be testing what you gave us thoroughly in the coming week;
I'll let you know how it works... or if we have additional questions.

Thanks!!

   Brian
Walter Wang [MSFT] - 04 Apr 2007 02:04 GMT
Hi Brian,

Thanks for your follow-up. Please feel free to reply here if the issue is
still not solved or you need anything else.

Regards,
Walter Wang (wawang@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
Brian - 22 May 2007 04:26 GMT
> Thanks for your follow-up. Please feel free to reply here if the issue is
> still not solved or you need anything else.

Here is a note from my colleague who is trying out your code...
he's going to continue playing with it to get a clearer idea of
what is happening... but I thought you might be able to give
some guidance...

When attempting to test this code I am receiving an error when I first hit a
key:

CallbackOnCollectedDelegate was detected
Message: A callback was made on a garbage collected delegate of type
'TCPSM!TCPSM.Utility.KeyboardHook+LowLevelKeyboardProc::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.

I placed the hook field in at the Program class level (as the example
showed) so it should not have been collected during the life of the
application run.  Not sure why this is happening.  I will go back try this
with a simpler test app to see if I can get it working.

-J
Walter Wang [MSFT] - 22 May 2007 09:05 GMT
Hi Brian,

Please modify the original code:

       public KeyboardHook()
       {
           _hookID = SetHook(new LowLevelKeyboardProc(HookCallback));
       }

to:

       private LowLevelKeyboardProc m_callback;
       public KeyboardHook()
       {
           m_callback = new LowLevelKeyboardProc(HookCallback);
           _hookID = SetHook(m_callback);
       }

This should fix it.

Regards,
Walter Wang (wawang@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
Walter Wang [MSFT] - 25 May 2007 03:07 GMT
Hi Brian,

Does the fix worked for you? The reason of this fix is to keep the delegate
at class level and the GC will not collect it later.

Let me know if there's anything unclear.

Regards,
Walter Wang (wawang@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
Brian - 22 Jun 2007 22:47 GMT
[Originally sent on May 23, 2007]

> Hi Brian,
>
> Please modify the original code:
...
> This should fix it.

And indeed it did!  Thanks.  Works... and its nice to be using a managed
hook vs. what we were doing.

Many thanks!!

   Brian
Walter Wang [MSFT] - 25 Jun 2007 02:45 GMT
Hi Brian,

Thanks for the confirmation.

Have a nice day.

Regards,
Walter Wang (wawang@online.microsoft.com, remove 'online.')
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
yepuri.jyothi@gmail.com - 10 Jul 2007 08:42 GMT
Hi Walter,

I am also facing same issue as Brain. We have hosted Word using DSO
Framer in our Application.

When user clicks certain shortcut like Ctrl+s, ESC, F5...application
should respond to these events...but Word is responding to these
events.

I have tried your solution, but its working only for single Keys not
for Ctrl+S. Also i need to bubble the event to be handled by my Form.

Control order is some thing like this

Application Form
TabControl
Panel
Axframer
Word

We tried with ProcessCmdKey. but not working

Thanks
jyothi

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.