UnityKinectDepthExplorer - how can I use this example with Kinect v1? - unity3d

I'm interested in displaying Depth data in Unity with Kinect for Windows. Unfortunately, I have Kinect v1.8 and I know this has been easily done with Kinect V2 (Kinect Fusion).
I found this example: https://github.com/rickbarraza/UnityKinectDepthExplorer
I installed all the necessary components and now getting DLLNOTFOUNDEXCEPTION:
Failed to load 'Assets/Plugins/x86_64/KinectUnityAddin.dll'
Concerning all the posts and forums I've been reading so far, It's because I'm using SDK 1.8 (instead of SDK 2.0).
Is there any way how I can use this example with Kinect v1.8? I tried to contact the author as well but he haven't responded back.
Thanks a lot!

I had the same Problem in an University Project maby its not to late for you.
This is an Kinect v1.8 Wrapper i made to read the kinect depth image only. I used the Kinect with MS-SDK from the Unity-Assetstore as an orientation, you dont have to download it. All you need is this Code.
Use The Init() Method to start and the GetDepthArray() Function to get the Deapth Frame.
hope it works for you !
You have to install the Kinect 1.8 sdk or have at least the Kinect10.dll from the 1.8 sdk in your Windows/System32 folder
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Runtime.InteropServices;
using System;
using System.Runtime.CompilerServices;
public class OwnKinectWrapper : MonoBehaviour {
DepthBuffer db;
#region Nui Variables/Structs/Intefraces
IntPtr streamReferenz;
public struct NuiImageViewArea
{
public int eDigitalZoom;
public int lCenterX;
public int lCenterY;
}
public struct NuiSurfaceDesc
{
uint width;
uint height;
}
public struct DepthBuffer
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 640 * 480, ArraySubType = UnmanagedType.U2)]
public ushort[] pixels;
}
public struct NuiLockedRect
{
public int pitch;
public int size;
public IntPtr pBits;
}
public struct NuiImageFrame
{
public Int64 liTimeStamp;
public uint dwFrameNumber;
public int eImageType;
public int eResolution;
public IntPtr pFrameTexture;
public uint dwFrameFlags_NotUsed;
public NuiImageViewArea ViewArea_NotUsed;
}
[Guid("13ea17f5-ff2e-4670-9ee5-1297a6e880d1")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[ComImport()]
public interface INuiFrameTexture
{
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
int BufferLen();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
int Pitch();
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
int LockRect(uint Level, ref NuiLockedRect pLockedRect, IntPtr pRect, uint Flags);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
int GetLevelDesc(uint Level, ref NuiSurfaceDesc pDesc);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
[PreserveSig]
int UnlockRect(uint Level);
}
#endregion
// Use this for initialization
public int Init() {
int init = 0;
try {
init = NuiInitialize(0x00000020);
Debug.Log("init : " + init);
streamReferenz = IntPtr.Zero;
NuiImageStreamOpen(4, 2, 0, 2, IntPtr.Zero, ref streamReferenz);
}
catch (DllNotFoundException e)
{
string message = "Please check the Kinect SDK installation.";
Debug.LogError(message);
Debug.LogError(e.ToString());
return -1;
}
catch (Exception e)
{
Debug.LogError(e.ToString());
return -1;
}
return init;
}
// Update is called once per frame
void Update()
{
IntPtr imageStreamFrameReferenz = IntPtr.Zero;
int test = NuiImageStreamGetNextFrame(streamReferenz, 0, ref imageStreamFrameReferenz);
if (test == 0) {
NuiImageFrame imageFrame = (NuiImageFrame)Marshal.PtrToStructure(imageStreamFrameReferenz, typeof(NuiImageFrame));
INuiFrameTexture frameTexture = (INuiFrameTexture)Marshal.GetObjectForIUnknown(imageFrame.pFrameTexture);
NuiLockedRect lockedRectPtr = new NuiLockedRect();
IntPtr r = IntPtr.Zero;
frameTexture.LockRect(0, ref lockedRectPtr, r, 0);
db = (DepthBuffer)Marshal.PtrToStructure(lockedRectPtr.pBits, typeof(DepthBuffer));
frameTexture.UnlockRect(0);
NuiImageStreamReleaseFrame(streamReferenz, imageStreamFrameReferenz);
}
}
void OnDisable() {
NuiShutdown();
}
public ushort[] GetDepthArray(){
return db.pixels;
}
[DllImportAttribute(#"Kinect10.dll",EntryPoint="NuiInitialize")]
public static extern int NuiInitialize (uint dwFlags);
[DllImportAttribute(#"Kinect10.dll", EntryPoint = "NuiImageStreamOpen")]
public static extern int NuiImageStreamOpen(int enumImageType,int enumImgageResolution, uint image_Flags, uint frameBufferLimit, IntPtr nextFrameEvent, ref IntPtr streamHandle );
[DllImportAttribute(#"Kinect10.dll", EntryPoint = "NuiImageStreamGetNextFrame")]
public static extern int NuiImageStreamGetNextFrame(IntPtr streamReferenz, uint dwMillisecondsToWait, ref IntPtr ImageFrameReferenz);
[DllImportAttribute(#"Kinect10.dll", EntryPoint = "NuiImageStreamReleaseFrame")]
public static extern int NuiImageStreamReleaseFrame(IntPtr phStreamHandle, IntPtr ppcImageFrame);
[DllImportAttribute(#"Kinect10.dll",EntryPoint="NuiDepthPixelToDepth")]
public static extern ushort NuiDepthPixelToDepth (ushort depthPixel);
[DllImportAttribute(#"Kinect10.dll", EntryPoint = "NuiShutdown")]
public static extern void NuiShutdown();
}
if something is not working or you need help feel free to write some lines

Related

How to use SHGetStockIconInfo in Powershell?

I'm trying to pull folder icons for a listview in a winform. I'm using [Drawing.Icon]::ExtractAssociatedIcon for file icons, but it doesn't work on folders.
I found this question here on stack which said to use SHGetStockIconInfo, but I can't wrap my head around how to load this function and use it in Powershell (I have no C programming experience). I managed to pull this from the linked question, but I'm stuck:
Add-Type -NameSpace WinAPI -Name DefaultIcons -MemberDefinition #'
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHSTOCKICONINFO {
public uint cbSize;
public IntPtr hIcon;
public int iSysIconIndex;
public int iIcon;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szPath;
}
[DllImport("shell32.dll")]
public static extern int SHGetStockIconInfo(uint siid, uint uFlags, ref SHSTOCKICONINFO psii);
[DllImport("user32.dll")]
public static extern bool DestroyIcon(IntPtr handle);
private const uint SHSIID_FOLDER = 0x3;
private const uint SHGSI_ICON = 0x100;
private const uint SHGSI_LARGEICON = 0x0;
private const uint SHGSI_SMALLICON = 0x1;
'#
This runs without error, but that's as far as I can get and I don't fully understand what's going on.
I know I need to call the function SHGetStockIconInfo with three parameters:
uint to identify what icon I want
uint flag for the size of icon I want
a reference to a SHSTOCKICONINFO structure
The question I got all this from includes a GetStockIcon function definition, but I keep getting errors trying to include it saying The type or namespace name 'Icon' could not be found (are you missing a using directive or an assembly reference?)
With a few adjustments I got the code from that C# question to work under both PowerShell 5.1 and 7.2.6.
$refAsm = if( $PSVersionTable.PSVersion.Major -le 5 ) {'System.Drawing'} else {'System.Drawing.Common'}
Add-Type -ReferencedAssemblies $refAsm -TypeDefinition #'
using System;
using System.Runtime.InteropServices;
using System.Drawing;
public static class DefaultIcons
{
public static Icon GetStockIcon(uint type, uint size)
{
var info = new SHSTOCKICONINFO();
info.cbSize = (uint)Marshal.SizeOf(info);
SHGetStockIconInfo(type, SHGSI_ICON | size, ref info);
var icon = (Icon)Icon.FromHandle(info.hIcon).Clone(); // Get a copy that does not use the original handle
DestroyIcon(info.hIcon); // Clean up native icon to prevent resource leak
return icon;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHSTOCKICONINFO
{
public uint cbSize;
public IntPtr hIcon;
public int iSysIconIndex;
public int iIcon;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szPath;
}
[DllImport("shell32.dll")]
public static extern int SHGetStockIconInfo(uint siid, uint uFlags, ref SHSTOCKICONINFO psii);
[DllImport("user32.dll")]
public static extern bool DestroyIcon(IntPtr handle);
public const uint SHSIID_FOLDER = 0x3;
public const uint SHGSI_ICON = 0x100;
public const uint SHGSI_LARGEICON = 0x0;
public const uint SHGSI_SMALLICON = 0x1;
}
'#
Use it like this:
$folderIconLarge = [DefaultIcons]::GetStockIcon( [DefaultIcons]::SHSIID_FOLDER, [DefaultIcons]::SHGSI_LARGEICON )
$folderIconSmall = [DefaultIcons]::GetStockIcon( [DefaultIcons]::SHSIID_FOLDER, [DefaultIcons]::SHGSI_SMALLICON )

Run powershell command as currently logged in user

Given a powershell script that runs as Local System (nt authority\system).
Is there a way to execute a command as the currently logged in user (without specifying the user password of course) ?
From what I've experimented so far is the Register-ScheduledTask cmdlet which takes an -User param. The task was scheduled and run successfully, but only works when the user is logged in.
Is there a better way to do it ?
I use schtasks.exe. I am not sure if this can be done in pure PS.
$user = Get-WmiObject -Class win32_computersystem | % Username
$computer = $env:COMPUTERNAME
$time = (Get-Date).AddMinutes(1).ToShortTimeString()
schtasks /create /s $computer /tn "RunCMD" /sc once /tr "cmd.exe" /st $time /ru $user
There is a complicated and round-about way of doing exactly this. It involves the API function CreateProcessAsUser. In order to call it, you need to obtain the TOKEN associated with the current console session, which can be done with the WTSQueryUserToken API function. This takes a session ID, which is obtained with the WTSGetActiveConsoleSessionId API function. (Many examples then show the token being duplicated, but from what I've read, this is unnecessary since WTSQueryUserToken already returns a primary token.)
You also need to initialize an environment block for the process you're going to create. For that, you use the CreateEnvironmentBlock API function. Make sure you specify the CREATE_UNICODE_ENVIRONMENT flag.
Of course, PowerShell cannot call these functions directly -- so you will have to dynamically compile some C# helper code and load it into the PowerShell environment.
Here is an article that has code to run notepad as the currently logged in user:
http://rzander.azurewebsites.net/create-a-process-as-loggedon-user/
Note: This solution looks like it requires the command be run from a system service due to how privileges are passed to child processes. Additionally the example does not work running from the system account because the working directory is not specified. Using the full path to the executable does work.
$Source = #"
using System;
using System.Runtime.InteropServices;
namespace murrayju.ProcessExtensions
{
public static class ProcessExtensions
{
#region Win32 Constants
private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
private const int CREATE_NO_WINDOW = 0x08000000;
private const int CREATE_NEW_CONSOLE = 0x00000010;
private const uint INVALID_SESSION_ID = 0xFFFFFFFF;
private static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
#endregion
#region DllImports
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private static extern bool CreateProcessAsUser(
IntPtr hToken,
String lpApplicationName,
String lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandle,
uint dwCreationFlags,
IntPtr lpEnvironment,
String lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
private static extern bool DuplicateTokenEx(
IntPtr ExistingTokenHandle,
uint dwDesiredAccess,
IntPtr lpThreadAttributes,
int TokenType,
int ImpersonationLevel,
ref IntPtr DuplicateTokenHandle);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
[DllImport("userenv.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hSnapshot);
[DllImport("kernel32.dll")]
private static extern uint WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll")]
private static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);
[DllImport("wtsapi32.dll", SetLastError = true)]
private static extern int WTSEnumerateSessions(
IntPtr hServer,
int Reserved,
int Version,
ref IntPtr ppSessionInfo,
ref int pCount);
#endregion
#region Win32 Structs
private enum SW
{
SW_HIDE = 0,
SW_SHOWNORMAL = 1,
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_MAX = 10
}
private enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
private enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
[StructLayout(LayoutKind.Sequential)]
private struct STARTUPINFO
{
public int cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
private enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation = 2
}
[StructLayout(LayoutKind.Sequential)]
private struct WTS_SESSION_INFO
{
public readonly UInt32 SessionID;
[MarshalAs(UnmanagedType.LPStr)]
public readonly String pWinStationName;
public readonly WTS_CONNECTSTATE_CLASS State;
}
#endregion
// Gets the user token from the currently active session
private static bool GetSessionUserToken(ref IntPtr phUserToken)
{
var bResult = false;
var hImpersonationToken = IntPtr.Zero;
var activeSessionId = INVALID_SESSION_ID;
var pSessionInfo = IntPtr.Zero;
var sessionCount = 0;
// Get a handle to the user access token for the current active session.
if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessionInfo, ref sessionCount) != 0)
{
var arrayElementSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
var current = pSessionInfo;
for (var i = 0; i < sessionCount; i++)
{
var si = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
current += arrayElementSize;
if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive)
{
activeSessionId = si.SessionID;
}
}
}
// If enumerating did not work, fall back to the old method
if (activeSessionId == INVALID_SESSION_ID)
{
activeSessionId = WTSGetActiveConsoleSessionId();
}
if (WTSQueryUserToken(activeSessionId, ref hImpersonationToken) != 0)
{
// Convert the impersonation token to a primary token
bResult = DuplicateTokenEx(hImpersonationToken, 0, IntPtr.Zero,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, (int)TOKEN_TYPE.TokenPrimary,
ref phUserToken);
CloseHandle(hImpersonationToken);
}
return bResult;
}
public static bool StartProcessAsCurrentUser(string appPath, string cmdLine = null, string workDir = null, bool visible = true)
{
var hUserToken = IntPtr.Zero;
var startInfo = new STARTUPINFO();
var procInfo = new PROCESS_INFORMATION();
var pEnv = IntPtr.Zero;
int iResultOfCreateProcessAsUser;
startInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
try
{
if (!GetSessionUserToken(ref hUserToken))
{
throw new Exception("StartProcessAsCurrentUser: GetSessionUserToken failed.");
}
uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
startInfo.lpDesktop = "winsta0\\default";
if (!CreateEnvironmentBlock(ref pEnv, hUserToken, false))
{
throw new Exception("StartProcessAsCurrentUser: CreateEnvironmentBlock failed.");
}
if (!CreateProcessAsUser(hUserToken,
appPath, // Application Name
cmdLine, // Command Line
IntPtr.Zero,
IntPtr.Zero,
false,
dwCreationFlags,
pEnv,
workDir, // Working directory
ref startInfo,
out procInfo))
{
throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.\n");
}
iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
}
finally
{
CloseHandle(hUserToken);
if (pEnv != IntPtr.Zero)
{
DestroyEnvironmentBlock(pEnv);
}
CloseHandle(procInfo.hThread);
CloseHandle(procInfo.hProcess);
}
return true;
}
}
}
"#
Add-Type -ReferencedAssemblies 'System', 'System.Runtime.InteropServices' -TypeDefinition $Source -Language CSharp
[murrayju.ProcessExtensions.ProcessExtensions]::StartProcessAsCurrentUser('c:\\windows\\system32\\notepad.exe')
You can use the portable powershell app deployment kit (Link). You can edit the deploy-application.ps1 with your code and run it elevated use/add Execute-ProcessAsUser in the script to run applications/scripts with the current user without a prompt for credentials.

Detecting text changes in Word 2016 from VSTO add-in

This question is very closely related to How to get the “KeyPress” event from a Word 2010 Addin (developed in C#)? (and in fact includes the sample code from the answer to that question), but this is specifically about developing in Visual Studio (Professional) 2015 for Word 2016 running in Windows 10.
I’m trying to detect when text changes in a Word document from a VSTO add-in. I understand from
How to get the “KeyPress” event from a Word 2010 Addin (developed in C#)? (Nov 14, 2011)
Capturing keydown event of MS Word using C# (Oct 21, 2012)
How to raise an event on MS word Keypress (Oct 24, 2012)
How to trap keypress event in MSword using VSTO? (Nov 5, 2012)
that there’s no event-driven way to do this. Word simply does not send events when text changes.
I’ve seen two workarounds discussed:
Use the WindowSelectionChange event. Unfortunately, this event appears to be sent when the selection is changed by pressing arrow keys, using the mouse, performing undo or redo, and probably other actions, but not when typing or deleting.
Use a low-level keydown event hook. This has been discussed in several of those StackOverflow questions, and was also called a “widely spread technique” in a thread on a Visual Studio forum in February 2014.
I’m trying to use the code in the answer to How to get the “KeyPress” event from a Word 2010 Addin (developed in C#)?, and it seems to observe every keydown event except those sent to Word 2016.
Here’s the code I’m using, for ease of reference.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
namespace KeydownWordAddIn
{
public partial class ThisAddIn
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static IntPtr hookId = IntPtr.Zero;
private delegate IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam);
private static HookProcedure procedure = HookCallback;
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, HookProcedure lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr SetHook(HookProcedure procedure)
{
using (Process process = Process.GetCurrentProcess())
using (ProcessModule module = process.MainModule)
return SetWindowsHookEx(WH_KEYBOARD_LL, procedure, GetModuleHandle(module.ModuleName), 0);
}
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int pointerCode = Marshal.ReadInt32(lParam);
string pressedKey = ((Keys)pointerCode).ToString();
// Do some sort of processing on key press.
var thread = new Thread(() => {
Debug.WriteLine(pressedKey);
});
thread.Start();
}
return CallNextHookEx(hookId, nCode, wParam, lParam);
}
private void ThisAddIn_Startup(object sender, EventArgs e)
{
hookId = SetHook(procedure);
}
private void ThisAddIn_Shutdown(object sender, EventArgs e)
{
UnhookWindowsHookEx(hookId);
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
When I run Word 2016 with this add-in, I see keydown events sent to the Edge browser and even Visual Studio, but not to Word itself.
Are keydown hooks somehow prevented in Word 2016, or am I doing something wrong?
Everthing should work fine if you don't use a low-level hook in your VSTO add-in.
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetCurrentThreadId();
const int WH_KEYBOARD = 2;
private static IntPtr SetHook(HookProcedure procedure)
{
var threadId = (uint)SafeNativeMethods.GetCurrentThreadId();
return SetWindowsHookEx(WH_KEYBOARD, procedure, IntPtr.Zero, threadId);
}
Please note that you probably also need to create a hook to intercept mouse messages as it is possible to modify the text of a document solely by mouse interactions (e.g. copy and paste via Ribbon or context menu).
VSTO Sample
Here is a complete working VSTO sample including keyboard and mouse hooks:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Office = Microsoft.Office.Core;
namespace SampleAddinWithKeyboardHook
{
public partial class ThisAddIn
{
// NOTE: We need a backing field to prevent the delegate being garbage collected
private SafeNativeMethods.HookProc _mouseProc;
private SafeNativeMethods.HookProc _keyboardProc;
private IntPtr _hookIdMouse;
private IntPtr _hookIdKeyboard;
private void ThisAddIn_Startup(object sender, EventArgs e)
{
_mouseProc = MouseHookCallback;
_keyboardProc = KeyboardHookCallback;
SetWindowsHooks();
}
private void ThisAddIn_Shutdown(object sender, EventArgs e)
{
UnhookWindowsHooks();
}
private void SetWindowsHooks()
{
uint threadId = (uint)SafeNativeMethods.GetCurrentThreadId();
_hookIdMouse =
SafeNativeMethods.SetWindowsHookEx(
(int)SafeNativeMethods.HookType.WH_MOUSE,
_mouseProc,
IntPtr.Zero,
threadId);
_hookIdKeyboard =
SafeNativeMethods.SetWindowsHookEx(
(int)SafeNativeMethods.HookType.WH_KEYBOARD,
_keyboardProc,
IntPtr.Zero,
threadId);
}
private void UnhookWindowsHooks()
{
SafeNativeMethods.UnhookWindowsHookEx(_hookIdKeyboard);
SafeNativeMethods.UnhookWindowsHookEx(_hookIdMouse);
}
private IntPtr MouseHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
var mouseHookStruct =
(SafeNativeMethods.MouseHookStructEx)
Marshal.PtrToStructure(lParam, typeof(SafeNativeMethods.MouseHookStructEx));
// handle mouse message here
var message = (SafeNativeMethods.WindowMessages)wParam;
Debug.WriteLine(
"{0} event detected at position {1} - {2}",
message,
mouseHookStruct.pt.X,
mouseHookStruct.pt.Y);
}
return SafeNativeMethods.CallNextHookEx(
_hookIdKeyboard,
nCode,
wParam,
lParam);
}
private IntPtr KeyboardHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
// handle key message here
Debug.WriteLine("Key event detected.");
}
return SafeNativeMethods.CallNextHookEx(
_hookIdKeyboard,
nCode,
wParam,
lParam);
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support.
/// </summary>
private void InternalStartup()
{
Startup += ThisAddIn_Startup;
Shutdown += ThisAddIn_Shutdown;
}
#endregion
}
internal static class SafeNativeMethods
{
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
public enum HookType
{
WH_KEYBOARD = 2,
WH_MOUSE = 7
}
public enum WindowMessages : uint
{
WM_KEYDOWN = 0x0100,
WM_KEYFIRST = 0x0100,
WM_KEYLAST = 0x0108,
WM_KEYUP = 0x0101,
WM_LBUTTONDBLCLK = 0x0203,
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MBUTTONDBLCLK = 0x0209,
WM_MBUTTONDOWN = 0x0207,
WM_MBUTTONUP = 0x0208,
WM_MOUSEACTIVATE = 0x0021,
WM_MOUSEFIRST = 0x0200,
WM_MOUSEHOVER = 0x02A1,
WM_MOUSELAST = 0x020D,
WM_MOUSELEAVE = 0x02A3,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_MOUSEHWHEEL = 0x020E,
WM_RBUTTONDBLCLK = 0x0206,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205,
WM_SYSDEADCHAR = 0x0107,
WM_SYSKEYDOWN = 0x0104,
WM_SYSKEYUP = 0x0105
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(
int idHook,
HookProc lpfn,
IntPtr hMod,
uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(
IntPtr hhk,
int nCode,
IntPtr wParam,
IntPtr lParam);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetCurrentThreadId();
[StructLayout(LayoutKind.Sequential)]
public struct Point
{
public int X;
public int Y;
public Point(int x, int y)
{
X = x;
Y = y;
}
public static implicit operator System.Drawing.Point(Point p)
{
return new System.Drawing.Point(p.X, p.Y);
}
public static implicit operator Point(System.Drawing.Point p)
{
return new Point(p.X, p.Y);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct MouseHookStructEx
{
public Point pt;
public IntPtr hwnd;
public uint wHitTestCode;
public IntPtr dwExtraInfo;
public int MouseData;
}
}
}
VBE Add-in Sample
And here is a working sample for the VBA editor (VBE add-in):
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Extensibility;
namespace VbeAddin
{
[ComVisible(true)]
[ProgId("VbeAddin.Connect")]
[Guid("95840C70-5A1A-4EDB-B436-40E8BF030469")]
public class Connect : StandardOleMarshalObject, IDTExtensibility2
{
// NOTE: We need a backing field to prevent the delegate being garbage collected
private SafeNativeMethods.HookProc _mouseProc;
private SafeNativeMethods.HookProc _keyboardProc;
private IntPtr _hookIdMouse;
private IntPtr _hookIdKeyboard;
#region IDTExtensibility2 Members
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
_mouseProc = MouseHookCallback;
_keyboardProc = KeyboardHookCallback;
SetWindowsHooks();
}
public void OnDisconnection(ext_DisconnectMode removeMode, ref Array custom)
{
UnhookWindowsHooks();
}
public void OnAddInsUpdate(ref Array custom)
{
}
public void OnStartupComplete(ref Array custom)
{
}
public void OnBeginShutdown(ref Array custom)
{
}
#endregion
private void SetWindowsHooks()
{
uint threadId = (uint)SafeNativeMethods.GetCurrentThreadId();
_hookIdMouse =
SafeNativeMethods.SetWindowsHookEx(
(int)SafeNativeMethods.HookType.WH_MOUSE,
_mouseProc,
IntPtr.Zero,
threadId);
_hookIdKeyboard =
SafeNativeMethods.SetWindowsHookEx(
(int)SafeNativeMethods.HookType.WH_KEYBOARD,
_keyboardProc,
IntPtr.Zero,
threadId);
}
private void UnhookWindowsHooks()
{
SafeNativeMethods.UnhookWindowsHookEx(_hookIdKeyboard);
SafeNativeMethods.UnhookWindowsHookEx(_hookIdMouse);
}
private IntPtr MouseHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
var mouseHookStruct =
(SafeNativeMethods.MouseHookStructEx)
Marshal.PtrToStructure(
lParam,
typeof(SafeNativeMethods.MouseHookStructEx));
// handle mouse message here
var message = (SafeNativeMethods.WindowMessages)wParam;
Debug.WriteLine(
"{0} event detected at position {1} - {2}",
message,
mouseHookStruct.pt.X,
mouseHookStruct.pt.Y);
}
return SafeNativeMethods.CallNextHookEx(
_hookIdKeyboard,
nCode,
wParam,
lParam);
}
private IntPtr KeyboardHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
// handle key message here
Debug.WriteLine("Key event detected.");
}
return SafeNativeMethods.CallNextHookEx(
_hookIdKeyboard,
nCode,
wParam,
lParam);
}
}
internal static class SafeNativeMethods
{
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
public enum HookType
{
WH_KEYBOARD = 2,
WH_MOUSE = 7
}
public enum WindowMessages : uint
{
WM_KEYDOWN = 0x0100,
WM_KEYFIRST = 0x0100,
WM_KEYLAST = 0x0108,
WM_KEYUP = 0x0101,
WM_LBUTTONDBLCLK = 0x0203,
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MBUTTONDBLCLK = 0x0209,
WM_MBUTTONDOWN = 0x0207,
WM_MBUTTONUP = 0x0208,
WM_MOUSEACTIVATE = 0x0021,
WM_MOUSEFIRST = 0x0200,
WM_MOUSEHOVER = 0x02A1,
WM_MOUSELAST = 0x020D,
WM_MOUSELEAVE = 0x02A3,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_MOUSEHWHEEL = 0x020E,
WM_RBUTTONDBLCLK = 0x0206,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205,
WM_SYSDEADCHAR = 0x0107,
WM_SYSKEYDOWN = 0x0104,
WM_SYSKEYUP = 0x0105
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(
int idHook,
HookProc lpfn,
IntPtr hMod,
uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(
IntPtr hhk,
int nCode,
IntPtr wParam,
IntPtr lParam);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetCurrentThreadId();
[StructLayout(LayoutKind.Sequential)]
public struct Point
{
public int X;
public int Y;
}
[StructLayout(LayoutKind.Sequential)]
public struct MouseHookStructEx
{
public Point pt;
public IntPtr hwnd;
public uint wHitTestCode;
public IntPtr dwExtraInfo;
public int MouseData;
}
}
}
I've experienced this same exact issue in Word 2013 and had to come up with a somewhat "creative" solution. It uses diffplex to monitor changes in the text of the active document and fires events when it changes. It's less than ideal but we do what we have to do to make things work.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Word = Microsoft.Office.Interop.Word;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Word;
using System.ComponentModel;
namespace WordUtils {
public class TextChangeDetector {
public Word.Application Application;
private BackgroundWorker bg;
public delegate void TextChangeHandler(object sender, TextChangedEventArgs e);
public event TextChangeHandler OnTextChanged;
public TextChangeDetector(Word.Application app) {
this.Application = app;
}
public void Start() {
bg = new BackgroundWorker();
bg.WorkerReportsProgress = true;
bg.WorkerSupportsCancellation = true;
bg.ProgressChanged += bg_ProgressChanged;
bg.DoWork += bg_DoWork;
bg.RunWorkerAsync(this.Application);
}
private void bg_ProgressChanged(object sender, ProgressChangedEventArgs e) {
switch (e.ProgressPercentage) {
case 50: //change
if (OnTextChanged != null) {
OnTextChanged(this, new TextChangedEventArgs((char)e.UserState));
}
break;
}
}
private void bg_DoWork(object sender, DoWorkEventArgs e) {
Word.Application wordApp = e.Argument as Word.Application;
BackgroundWorker bg = sender as BackgroundWorker;
string lastPage = string.Empty;
while (true) {
try {
if (Application.Documents.Count > 0) {
if (Application.ActiveDocument.Words.Count > 0) {
var currentPage = Application.ActiveDocument.Bookmarks["\\Page"].Range.Text;
if (currentPage != null && currentPage != lastPage) {
var differ = new DiffPlex.Differ();
var builder = new DiffPlex.DiffBuilder.InlineDiffBuilder(differ);
var difference = builder.BuildDiffModel(lastPage, currentPage);
var change = from d in difference.Lines where d.Type != DiffPlex.DiffBuilder.Model.ChangeType.Unchanged select d;
if (change.Any()) {
bg.ReportProgress(50, change.Last().Text.Last());
}
lastPage = currentPage;
}
}
}
} catch (Exception) {
}
if (bg.CancellationPending) {
break;
}
System.Threading.Thread.Sleep(100);
}
}
public void Stop() {
if (bg != null && !bg.CancellationPending) {
bg.CancelAsync();
}
}
}
public class TextChangedEventArgs : EventArgs {
public char Letter;
public TextChangedEventArgs(char letter) {
this.Letter = letter;
}
}
}
Usage:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Word = Microsoft.Office.Interop.Word;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Tools.Word;
using WordUtils;
namespace WordAddIn1 {
public partial class ThisAddIn {
TextChangeDetector detector;
private void ThisAddIn_Startup(object sender, System.EventArgs e) {
detector = new TextChangeDetector(Application);
detector.OnTextChanged += detector_OnTextChanged;
detector.Start();
}
void detector_OnTextChanged(object sender, TextChangedEventArgs e) {
Console.WriteLine(e.Letter);
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e) {
detector.Stop();
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup() {
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}

openprinter with winspool.drv not working

As a part of my project I am learning how to handle the printers using "winspool.drv" and "PRINTUI.DLL,PrintUIEntry" to which I am new. I am using powershell for this project. The problem is that my code is throwing an error when I am trying to get printer Handle with openprinter method
Error: Method invocation failed because [OpenPrinter1.Program1] does not contain a method named 'OpenPrinterHandle'.
Code:
$code = #'
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
namespace OpenPrinter1
{
public class Program1
{
[DllImport("winspool.drv", EntryPoint = "OpenPrinter", SetLastError =true)]
internal static extern bool OpenPrinter(string pPrinterName, ref IntPtr phPrinter, PRINTER_DEFAULTS pDefault);
[DllImport("winspool.drv", EntryPoint = "ClosePrinter", SetLastError = true)]
internal static extern int ClosePrinter(IntPtr hPrinter);
[StructLayout(LayoutKind.Sequential)]
public class PRINTER_DEFAULTS
{
public string pDatatype;
public IntPtr pDevMode;
public int DesiredAccess;
}
public struct OpenPrinterAccessCodes
{
public const int DELETE = 0x10000; // DELETE - Allowed to delete printers
public const int READ_CONTROL = 0x20000; // READ_CONTROL -
public const int WRITE_DAC = 0x40000; // WRITE_DAC -
public const int WRITE_OWNER = 0x80000; // WRITE_OWNER -
public const int SERVER_ACCESS_ADMINISTER = 0x1;
public const int SERVER_ACCESS_ENUMERATE = 0x2;
public const int PRINTER_ACCESS_ADMINISTER = 0x4;
public const int PRINTER_ACCESS_USE = 0x8;
public const int STANDARD_RIGHTS_REQUIRED = 0xF0000;
public const int PRINTER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED |PRINTER_ACCESS_ADMINISTER | PRINTER_ACCESS_USE);
public const int SERVER_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVER_ACCESS_ADMINISTER | SERVER_ACCESS_ENUMERATE);
public const int MAX_PORTNAME_LEN = 64;
public const int MAX_NETWORKNAME_LEN = 49;
public const int MAX_SNMP_COMMUNITY_STR_LEN = 33;
public const int MAX_QUEUENAME_LEN = 33;
public const int MAX_IPADDR_STR_LEN = 16;
public const int ERROR_INSUFFICIENT_BUFFER = 122;
public const int ERROR_INVALID_FLAGS = 1004;
}
public IntPtr OpenPrinterHandle(string printerName)
{
var def = new PRINTER_DEFAULTS { pDatatype = null, pDevMode = IntPtr.Zero, DesiredAccess = OpenPrinterAccessCodes.PRINTER_ALL_ACCESS };
var hPrinter = IntPtr.Zero;
if (!OpenPrinter(printerName, ref hPrinter, def))
{
var lastWin32Error = new Win32Exception(Marshal.GetLastWin32Error());
throw lastWin32Error;
}
return hPrinter;
}
}
}
'#
cls
Add-Type -TypeDefinition $code -Language CSharp
if(!([OpenPrinter1.Program1]:: OpenPrinterHandle("hp LaserJet 1320 PCL 6 (Copy 1)")))
{
throw (New-Object componentmodel.win32Exception )
}
This syntax:
[Namespace.Class]::Method()
denotes invocation of a static method. The OpenPrinterHandle() method in your type definition is an instance method.
To change the behavior, just introduce the static keyword in the method signature:
public static IntPtr OpenPrinterHandle(string printerName)
and then you should be able to do:
[OpenPrinter1.Program1]::OpenPrinterHandle($printername)

how to capture clicks event on other window that has been minimized

i want to build an app that work in the background, and will capture all click events
on the minimize button, of all opened forms / windows that actually running. (not only in my current app)
it will be some sort of hook to add minimize handler to all of other windows.
how to setup this kind of hook ? ( please provide some code example in csharp with marsheling )
To better understand the idea : this procedure already exists in program called TrayIt that handle Ctrl+Click on the Minimize button, and send programs to system tray .
EDIT:
i have found that SetWindowsHookEx cannot set a global hook with c# due to limitation in manged code (see the msdn documentation )
but may WinEventProc with EVENT_OBJECT_STATECHANGE should do the work
finely i have found solution for this hook ,
this is not the best solution that i can get but it do the work
i have mixed window_state_change in SetWinEventHook
and component to track Control Key in Gma.UserActivityMonitor
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Windows;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Security.Permissions;
using Gma.UserActivityMonitor;
namespace example {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
public const uint WINEVENT_OUTOFCONTEXT = 0;
public const uint EVENT_OBJECT_STATECHANGE = 0x800A;
[DllImport("user32.dll")]
public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
public static extern bool UnhookWinEvent(IntPtr hWinEventHook);
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
public static bool ControlDown = false;
public static IntPtr hhook;
static WinEventDelegate procDelegate = new WinEventDelegate(WinEventProc);
private void load(object sender, System.EventArgs e) {
hhook = SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE, IntPtr.Zero, procDelegate, 0, 0, winapi.WINEVENT_OUTOFCONTEXT);
HookManager.KeyDown += HookManager_KeyDown;
HookManager.KeyUp += HookManager_KeyUp;
}
private void closing(object sender, System.Windows.Forms.FormClosingEventArgs e) {
UnhookWinEvent(hhook);
HookManager.KeyDown -= HookManager_KeyDown;
HookManager.KeyUp -= HookManager_KeyUp;
}
private void HookManager_KeyUp(object sender, KeyEventArgs e) {
if (e.KeyCode == Keys.LControlKey) { ControlDown = false; }
}
private void HookManager_KeyDown(object sender, KeyEventArgs e) {
if (e.KeyCode == Keys.LControlKey) { ControlDown = true; }
}
static void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) {
if (idObject == -2 && idChild == 2) {
if (ControlDown) {
// HookWindow(hwnd);
.....
}
}
}
}
}
if you like you can setup a simple hook with RegisterHotKey
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);