Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
318 views
in Technique[技术] by (71.8m points)

c# - Sending CTRL-S message to a window

I want to save a TextPad window using C# code; I can find out the handle of the window but not sure how to send CTRL - S to that window. I want to use P/Invoke API to achieve this. Also, that TextPad window will be inactive, because my application will be active at that time.

[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hwnd, int msg, int wParam, int lParam);

Send Ctrl+Up to a window

I looked at this discussion which is very similar to my problem. I understand logically that I have to do 4 send messages like below

  • KeyDown CTRL key
  • KeyDown S key
  • KeyUp S key
  • KeyUp CTRL key

I am not sure how to send the right parameters to the SendMessage. To close the window I use

SendMessage(hWnd, 0x0010, 0, 0);

I got this from MSDN library.

Can you please direct me to some link which tells me the hexadecimal for keys in the keyboard and explains what the last two parameters represent?

UPDATE - 1
Using spy++ I find these events generated with I press CTRL-S on Notepad window

1. WM_KEYDOWN nVirtKey:VK_Control, 
2. WM_KEYDOWN nVirtKey:'S' .. some other messates ..
3. WM_KEYUP nVirtKey:VK_Control. 
4. WM_KEYUP nVirtKey:'S'. 

UPDATE - 2


       private IntPtr startnotepad() {
            ProcessStartInfo psi = new ProcessStartInfo();
            psi.FileName = @"notepad.exe";
            String fileName = baseDirectory + textbox1.Text;
            psi.Arguments = @"""" + fileName + @"""";
            psi.WindowStyle = ProcessWindowStyle.Minimized;
            Process p = Process.Start(psi); 
            return p.MainWindowHandle;
        }

        private void SaveNotepad(IntPtr handle)
        {
            IntPtr handle = GetWindow(handle, 5); // get the keyboard focus handle
            // verified the handle with Spy ++.
            SendMessage(handle, 0x0100, 0x11, 0); // keydown ctrl
            SendMessage(handle, 0x0100, 0x53, 0); // keydown S
            //SendMessage(handle, 0x0101, 0x11, 0); --- I tried keeping "Keyup Ctrl" here as well.
            SendMessage(handle, 0x0101, 0x53, 0); // keyup s
            SendMessage(handle, 0x0101, 0x11, 0); // keyup ctrl            
        }

This code does not work (save part of it) even though I am able to see the WM_KEYDOWN - CTRL .. WM_KEYDOWN - 'S' .. KEYUP 'S' and KEYUP CTRL being sent to the right window in spy++. Can anyone comment what is wrong with this code? Or any suggestions if I am doing something really stupid.

UPDATE 3

I should be using PostMessage instead of SendMessage as @Hans suggested in his comments.


 [DllImport("user32.dll")]
 public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);  

        private void Save(IntPtr mainWindowHandle)
        {               
            IntPtr handle = GetWindow(mainWindowHandle, 5); // getChild window
            IntPtr CTRL_KEY = new IntPtr(0x11);
            uint KEY_DOWN = 0x0100;
            uint KEY_UP = 0x0101;
            IntPtr S_KEY = new IntPtr(0x53);

            //SetForegroundWindow(p.MainWindowHandle);
            PostMessage(handle, KEY_DOWN, CTRL_KEY, IntPtr.Zero);
            PostMessage(handle, KEY_DOWN, S_KEY, IntPtr.Zero);
            PostMessage(handle, KEY_UP, S_KEY, IntPtr.Zero);
            PostMessage(handle, KEY_UP, CTRL_KEY, IntPtr.Zero);                      
        } 

The above code instead of CTRL+S sends CTRL and S to Notepad window. So, I can see two "S" being thrown at Notepad. Looking at the real message generated when we press CTRL+S, I see that last parameter of my Postmessage is wrong. It should be something like (for KEY UP CTRL key "C01F0001")

Can you please tell me how to pass this hexadecimal as last parameter of postmessage?


// does not work
PostMessage(handle, KEY_UP, CTRL_KEY, new IntPtr(0xC01F0001);

Update 4 : I think we cannot send "hot key" messages to a minimized window. using Post Message.
This below code works with SendInput: but it will pop up the window, which kind a mar the purpose. Anyways, just wanted to update this thread.


 private void Save_Notepad(IntPtr mainWindowHandle) {
            //SetActiveWindow(mainWindowHandle);
            //SetFocus(GetWindow(mainWindowHandle, 5));
            ShowWindow(mainWindowHandle, 1); // show window 
            SetForegroundWindow(mainWindowHandle);
            //SetActiveWindow(mainWindowHandle);
            //SetFocus(GetWindow(mainWindowHandle, 5));
            //IntPtr returnvalue = SetFocus(mainWindowHandle);
            uint intReturn;
            INPUT structInput;
            structInput = new INPUT();
            structInput.type = 1;// keyboard input
            // key down
            structInput.ki.wScan = 0x1D;
            structInput.ki.time = 0;
            structInput.ki.dwFlags = 0;
            // key down Ctrl
            structInput.ki.wVk = 0x11;  //0x1D; //
            intReturn = SendInput(1, ref structInput, Marshal.SizeOf(new INPUT()));
            // key down S
            structInput.ki.wScan = 0x1F;
            structInput.ki.wVk = 0x53; //0x41;//0x53;  //0x1F;//
            intReturn = SendInput(1, ref structInput, Marshal.SizeOf(new INPUT()));
            // key up 
            structInput.ki.dwFlags = 0x0002; // key up
            // key up S
            intReturn = SendInput(1, ref structInput, Marshal.SizeOf(typeof(INPUT)));
            // key up CTRL
            structInput.ki.wVk = 0x11;  //0x1D; //
            intReturn = SendInput(1, ref structInput, Marshal.SizeOf(new INPUT()));
            //ShowWindow(mainWindowHandle, 2); // minimize it again 
        }

After CTRL + S I can minimize the window but then it will create a flash. Can anyone suggest if I can achieve this functionality without the "FLASH" (at least)?
UPDATE 5 : using WM_SYSCOMMAND


IntPtr handle = GetWindow(mainWindowHandle, 5);
// send Alt F message to Notepad.
// http://msdn.microsoft.com/en-us/library/ms646360(v=VS.85).aspx
// I can see this is working.
PostMessage(handle, 0x0112, 0xF100, 'f');  // send WM_SYSCOMMAND
// how to send s on this window ??
// I have tried things which I have learned so far. 

I just need to send S messages to file menu which will pop up as a result of WM_SYSCOMMAND. Can anyone point me to a documentation to how to do that?


PostMessage(handle, KEY_DOWN, S_KEY, 0x1F0001); // POST does not work
// tried with mainwindowhandle as well
PostMessage(handle, 0x111, 'S', 0); // WM_COMMAND does not work
PostMessage(handle, 0x0112, 0xF100, 's');  // WM_SYSCOMMAND does not work (and does not make sence either)

Final Update

I was not able to send ^S message to a minimized window. I am using sendkeys(^s) every 2-3 seconds when the focus is on an editor.

-- Karephul

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You cannot use SendMessage (or PostMessage, the correct one) to simulate the state of the modifiers keys, like CTRL. You must use SendInput().

A keystroke like Ctrl+S is not untypically translated into a WM_COMMAND message. Use the Spy++ tool to see what happens when you type Ctrl+S by hand. If you see WM_COMMAND then you're golden, you can use SendMessage() to send that message. This will of course only work on a specific process.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...