J
Josef Meile
Hi
On my previous post:
"Disabling CTRL-X shortcut in Visio 2003 Addon fails"
I could disable the CTRL-X shortcut by setting a keyboard hook with the
SetWindowsHookEx function of the Windows API. The only problem here is that
the shortcut gets disabled for the whole visio application and not for the
opened documents belonging to my C# addon. This is how I did it:
//KeyHookHandler is a method I defined on the same class
//VisioApp is a Visio.Application object
mKeyHookHandle = SetWindowsHookEx(WH_KEYBOARD,
new HOOKPROC(KeyHookHandler),
(IntPtr)0,
VisioApp.ProcessID);
theoretically you could use either the threadID or processID of the current
ActiveWindow instead of the processID from visio; however, I haven't
succeeded here. I tried to get them with the GetWindowThreadProcessId and
called the SetWindowsHookEx function with them, but I the hook isn't set.
This is what I have done so far:
First I defined GetWindowThreadProcessId like this:
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out
IntPtr lpdwProcessId);
I have tried this in the handler of the visEvtCodeDocCreate event:
Visio.Window docWindow = GetDocumentWindow(VisioApp.ActiveDocument);
IntPtr processId = (IntPtr)0;
IntPtr threadId = GetWindowThreadProcessId((IntPtr)docWindow.WindowHandle32,
out processId);
This is my GetDocumentWindow method:
public static Visio.Window GetDocumentWindow(Visio.Document vsoDocument)
{
foreach (Visio.Window vsoWindow in vsoDocument.Application.Windows)
{
if (vsoWindow.Document.FullName == vsoDocument.FullName)
return vsoWindow;
}
return null;
}
Now this is what I have done to set the hook:
mKeyHookHandle = SetWindowsHookEx(WH_KEYBOARD_LL,
new CSystemUtils.HOOKPROC(KeyHookHandler),processId,(IntPtr)0);
Or:
mKeyHookHandle = SetWindowsHookEx(WH_KEYBOARD_LL,
new CSystemUtils.HOOKPROC(KeyHookHandler),(IntPtr)0,threadId);
However mKeyHookHandle is always zero (0) and the error code returned by
Marshal.GetLastWin32Error(); is always 87 = "Wrong parameter". What am I
doing wrong here?
Another approach of solving this problem, which didn't work as well, is by
making a desicion on the keyboard hook as follows:
//Please note that I have a class attribute called Applications, where
//I have stored each opened document, which was created with my
//addon
private int KeyHookHandler(int nCode, IntPtr wParam, IntPtr lParam)
{
if (Applications.Contains(VisioApp.ActiveDocument.ID)) //It fails here
{
KeyboardHookStruct keyboardHookStruct = (KeyboardHookStruct)
Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
KeyEventArgs keyArgs = new KeyEventArgs((Keys)keyboardHookStruct.vkCode);
if (keyArgs.KeyCode == Keys.X)
{
int ctrlState = GetKeyState((int)VK_CTRL);
if ((ctrlState != 0) && (ctrlState != 1))
{
//This means that the ctrl key is also pressed. So, we return 1 to
disable it
return 1;
}
}
}
//Otherwise, the default actions will be excecuted.
return CallNextHookEx(mKeyHookHandle,nCode,wParam,lParam);
}
However, as soon as I try to access VisioApp, I get:
"An outgoing call cannot be made since the application is dispatching an
input-synchronous call."
Which I have solved in the past by doing something like this:
private delegate int myDelegate(args1, ..., argn);
public int myFunction(args1, ..., argn)
{
if (this.InvokeRequired)
return (System.Int32)this.Invoke(new myDelegate(myFunction),
new object[] {args1, ..., argn});
//Here code whatever myFunction is supposed to do
}
However, on this case "this.InvokeRequired" is always false (I already
tested this). Is there anyway of asking Visio for the ID of the current
document from a different thread?
Best regards
Josef
On my previous post:
"Disabling CTRL-X shortcut in Visio 2003 Addon fails"
I could disable the CTRL-X shortcut by setting a keyboard hook with the
SetWindowsHookEx function of the Windows API. The only problem here is that
the shortcut gets disabled for the whole visio application and not for the
opened documents belonging to my C# addon. This is how I did it:
//KeyHookHandler is a method I defined on the same class
//VisioApp is a Visio.Application object
mKeyHookHandle = SetWindowsHookEx(WH_KEYBOARD,
new HOOKPROC(KeyHookHandler),
(IntPtr)0,
VisioApp.ProcessID);
theoretically you could use either the threadID or processID of the current
ActiveWindow instead of the processID from visio; however, I haven't
succeeded here. I tried to get them with the GetWindowThreadProcessId and
called the SetWindowsHookEx function with them, but I the hook isn't set.
This is what I have done so far:
First I defined GetWindowThreadProcessId like this:
[DllImport("user32.dll", SetLastError = true)]
internal static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out
IntPtr lpdwProcessId);
I have tried this in the handler of the visEvtCodeDocCreate event:
Visio.Window docWindow = GetDocumentWindow(VisioApp.ActiveDocument);
IntPtr processId = (IntPtr)0;
IntPtr threadId = GetWindowThreadProcessId((IntPtr)docWindow.WindowHandle32,
out processId);
This is my GetDocumentWindow method:
public static Visio.Window GetDocumentWindow(Visio.Document vsoDocument)
{
foreach (Visio.Window vsoWindow in vsoDocument.Application.Windows)
{
if (vsoWindow.Document.FullName == vsoDocument.FullName)
return vsoWindow;
}
return null;
}
Now this is what I have done to set the hook:
mKeyHookHandle = SetWindowsHookEx(WH_KEYBOARD_LL,
new CSystemUtils.HOOKPROC(KeyHookHandler),processId,(IntPtr)0);
Or:
mKeyHookHandle = SetWindowsHookEx(WH_KEYBOARD_LL,
new CSystemUtils.HOOKPROC(KeyHookHandler),(IntPtr)0,threadId);
However mKeyHookHandle is always zero (0) and the error code returned by
Marshal.GetLastWin32Error(); is always 87 = "Wrong parameter". What am I
doing wrong here?
Another approach of solving this problem, which didn't work as well, is by
making a desicion on the keyboard hook as follows:
//Please note that I have a class attribute called Applications, where
//I have stored each opened document, which was created with my
//addon
private int KeyHookHandler(int nCode, IntPtr wParam, IntPtr lParam)
{
if (Applications.Contains(VisioApp.ActiveDocument.ID)) //It fails here
{
KeyboardHookStruct keyboardHookStruct = (KeyboardHookStruct)
Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
KeyEventArgs keyArgs = new KeyEventArgs((Keys)keyboardHookStruct.vkCode);
if (keyArgs.KeyCode == Keys.X)
{
int ctrlState = GetKeyState((int)VK_CTRL);
if ((ctrlState != 0) && (ctrlState != 1))
{
//This means that the ctrl key is also pressed. So, we return 1 to
disable it
return 1;
}
}
}
//Otherwise, the default actions will be excecuted.
return CallNextHookEx(mKeyHookHandle,nCode,wParam,lParam);
}
However, as soon as I try to access VisioApp, I get:
"An outgoing call cannot be made since the application is dispatching an
input-synchronous call."
Which I have solved in the past by doing something like this:
private delegate int myDelegate(args1, ..., argn);
public int myFunction(args1, ..., argn)
{
if (this.InvokeRequired)
return (System.Int32)this.Invoke(new myDelegate(myFunction),
new object[] {args1, ..., argn});
//Here code whatever myFunction is supposed to do
}
However, on this case "this.InvokeRequired" is always false (I already
tested this). Is there anyway of asking Visio for the ID of the current
document from a different thread?
Best regards
Josef