Ключи SendInput на машинах Win32 и Win64

Я использовал sendInput() под xp 32bits, используя веб-сервисы, чтобы нажать F5 для текущих сфокусированных окон. Теперь под Vista win64 я не могу получить этот результат. В некоторых статьях указываются проблемы с использованием 4-битной или 8-битной версии, но это не устраняет проблему под Vista с дифференциальной компиляцией и FieldOffset(4)или(8). Другие говорят о прекращении взаимодействия между экраном Vista и окном с помощью этого метода SendInput(). Может кто-нибудь указать решение для нажатия F5 на машинах win32 и win64. Спасибо.

uint intReturn = 0;
NativeWIN32.INPUT structInput;
structInput = new NativeWIN32.INPUT();
structInput.type = (uint)1;
structInput.ki.wScan = 0;
structInput.ki.time = 0;
structInput.ki.dwFlags = 0;
structInput.ki.dwExtraInfo = IntPtr.Zero; 

// Key down the actual key-code 
structInput.ki.wVk = (ushort)NativeWIN32.VK.F5;
//vk; 
intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
// Key up the actual key-code 
structInput.ki.dwFlags = NativeWIN32.KEYEVENTF_KEYUP;
structInput.ki.wVk = (ushort)NativeWIN32.VK.F5;
//vk; 
intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));



public class NativeWIN32
{ 
    public const ushort KEYEVENTF_KEYUP = 0x0002; 
    public enum VK : ushort 
    {  
        F5                   = 0x74,  
    } 

    public struct KEYBDINPUT 
    {  
        public ushort wVk;  
        public ushort wScan;  
        public uint dwFlags;  
        public long time;  
        public uint dwExtraInfo; 
    }; 
    [StructLayout(LayoutKind.Explicit,Size=28)]  
    public struct INPUT 
    {  
        [FieldOffset(0)] 
        public uint type;
        #if x86 
    //32bit 
    [FieldOffset(4)] 
        #else
        //64bit 
        [FieldOffset(8)]
        #endif
        public KEYBDINPUT ki; 
    };

    [DllImport("user32.dll")] 
    public static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);

}


person user325558    schedule 04.01.2011    source источник
comment
Пожалуйста, покажите нам свои декларации.   -  person SLaks    schedule 04.01.2011
comment
Действие: нажмите F5 из веб-приложения под Vista64 и после этого из Win7-64.   -  person user325558    schedule 04.01.2011
comment
Кажется, этот парень заработал. social.msdn.microsoft.com/ Форумы/en/windowscompatibility/thread/   -  person Brandon Boone    schedule 04.01.2011
comment
Интересно, Брэндон, но в этом коде я использую условную структуру ввода, чтобы справиться с этой проблемой, как ребята, но все еще не работает.   -  person user325558    schedule 04.01.2011
comment
Эта отличная библиотека inputsimulator.codeplex.com   -  person reggaeguitar    schedule 16.04.2014


Ответы (2)


Я столкнулся с этой проблемой с 32/64 на XP, и это решение, которое я придумал. Я не эксперт pInvoke, поэтому может быть более элегантное решение.

Основная причина, по-видимому, заключается в том, что размер слова различается между двумя архитектурами. Это приводит к тому, что некоторые сложные данные анализируются из структур данных, используемых во внешнем вызове. Мне пришлось объявить два отдельных набора структур и внешних вызовов для 64-битной и 32-битной версии.

internal static class SendInputExternalCalls
{
    // This SendInput call uses the 32bit input structure.
    [DllImport("user32.dll", SetLastError = true, EntryPoint = "SendInput")]
    public static extern UInt32 SendInput(
        UInt32 numInputs,
        [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)]
        SEND_INPUT_FOR_32_BIT[] sendInputsFor,
        Int32 cbSize);

    // This SendInput call uses the 64bit input structure.
    [DllImport("user32.dll", SetLastError = true, EntryPoint = "SendInput")]
    public static extern UInt32 SendInput(
        UInt32 numInputs,
        [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] 
        SEND_INPUT_FOR_64_BIT[] sendInputsFor,
        Int32 cbSize);
}

// This is the basic structure for 32 bit input.  SendInput allows for other input   
// types, but I was only concerned with keyboard input, so I harcoded my strucs that way.
[StructLayout(LayoutKind.Explicit, Pack = 1)]
internal struct SEND_INPUT_FOR_32_BIT
{
    [FieldOffset(0)]
    public uint InputType;  
    [FieldOffset(4)]
    public KEYBOARD_INPUT_FOR_32_BIT KeyboardInputStruct; 
}

// Here is the structure for keyboard input.  The key code, scan code, and flags
// are what's important.  The other variables are place holders so that the structure
// maintains the correct size when compared to the other possible input structure types.  
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct KEYBOARD_INPUT_FOR_32_BIT
{
    public ushort VirtualKeyCode;
    public ushort ScanCode;
    public uint Flags;
    public uint Time;
    public uint ExtraInfo;
    public uint Padding1;
    public uint Padding2;
}

// Here's the corresponding 64 bit structure.  Notice that the field offset are larger. 
[StructLayout(LayoutKind.Explicit, Pack = 1)]
internal struct SEND_INPUT_FOR_64_BIT
{
    [FieldOffset(0)]
    public uint InputType;
    [FieldOffset(8)]
    public KEYBOARD_INPUT_FOR_64_BIT KeyboardInputStruct;
}

// Here's the keyboard 64 bit structure.  Notice that the field offset are again larger.
[StructLayout(LayoutKind.Explicit, Pack = 1)]
internal struct KEYBOARD_INPUT_FOR_64_BIT
{
    [FieldOffset(0)]
    public ushort VirtualKeyCode;
    [FieldOffset(2)]
    public ushort ScanCode;
    [FieldOffset(4)]
    public uint Flags;
    [FieldOffset(12)]
    public uint Time;
    [FieldOffset(20)]
    public uint Padding1;
    [FieldOffset(28)]
    public uint Padding2;
} 

А вот и немного грязная часть. Какая структура будет использоваться, определяется архитектурой, на которой работает приложение. Вы можете скомпилировать для 32- или 64-битной цели, но вы все равно можете запустить 32-битное скомпилированное приложение в 64-битной Windows. Если вы хотите, чтобы ваше 32-битное скомпилированное приложение использовало SendInput на 64-битной машине, вам нужно выяснить, какую структуру использовать во время выполнения. Я сделал это, проверив размер слова, когда был вызван мой общедоступный метод для отправки ввода.

    public static void SendInput( ushort charUnicode )
    {
        // In 32 bit the IntPtr should be 4; it's 8 in 64 bit.
        if (Marshal.SizeOf(new IntPtr()) == 8)
        {
            SendInput64(charUnicode);
        }
        else
        {
            SendInput32(charUnicode);
        }
    }

Я не пробовал это в Vista, но это работает в 32/64 Windows XP и 32/64 Windows 7.

person CaulynDarr    schedule 30.04.2012
comment
более простое решение объяснено на pinvoke.net, где объединение помещены в отдельную структуру, чтобы автоматически решить эту проблему выравнивания: Выделяя объединение в отдельную структуру, а не помещая поля mi, ki и hi непосредственно в структуру INPUT, мы гарантируем, что структура .Net будет иметь правильное выравнивание как на 32-битной, так и на 64-битной версии. - person Steven Jeuris; 15.05.2013
comment
Где находятся методы SendInput64 (что угодно char) и SendInput32 (что угодно char)? - person reggaeguitar; 15.04.2014
comment
@reggaeguitar Я не перечислял их, но они очень простые. Это просто вспомогательные методы, которые делают внешний вызов с соответствующей разрядности системы структурой. - person CaulynDarr; 16.04.2014

Скомпилируйте свой проект для 32-битной версии, чтобы исправить это. См.: http://social.msdn.microsoft.com/Forums/en-SG/Vsexpressvb/thread/69e5529e-372b-4d70-bb94-556507a2358e

person Kashi Reddy    schedule 18.08.2011
comment
Это не решение проблемы. Это просто бессмысленный обходной путь. - person Alexandru Dicu; 04.02.2013