I have a C# program. The program creates an Adobe Reader process and prints a PDF document. It works fine in Windows XP, but does not work in Windows 7. I have checked that the AcroRd32.exe path is correct in Windows 7. The FindWindow method always returns 0 in Windows 7.
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("User32.dll")]
public static extern IntPtr FindWindow(string ClassN, string WindN);
[DllImport("user32.dll", EntryPoint = "SendMessageA")]
private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("shell32.dll ")]
public static extern int ShellExecute(IntPtr hwnd, string lpszOp, string lpszFile, string lpszParams, string lpszDir, int FsShowCmd);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern uint WinExec(string lpCmdLine, uint uCmdShow);
public bool isAcrobatExsists(string acrobatLoc)
{
IntPtr currentHandle = getWindowHandlerByClass("AcrobatSDIWindow");
if (currentHandle != IntPtr.Zero)
{
return true;
}
return false;
}
private static IntPtr getWindowHandlerByClass(string className)
{
IntPtr currentHandle = FindWindow(className, null);
return currentHandle;
}
private static IntPtr getWindowHandlerByName(string appName)
{
IntPtr currentHandle = FindWindow(null, appName);
return currentHandle;
}
Findwindow can depend a great deal on how you are running the application. It sounds like you might be running it as a scheduled task or a windows service. These run in a different session than what the user's desktop window is in, so it won't see or be able to interact with them.
They introduced this change in Windows Vista, so applications that do this will work just fine in XP but fail in Windows Vista or later.
Here's a link from msdn about it: Application Compatibility: Session 0 isolation
Related
The application will be installed by users from different countries, and what languages the keyboard layout of a specific user is unknown. We need a way with which the keyboard layout will change.
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool PostMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
public void ChangeLanguage()
{
PostMessage(GetForegroundWindow(), 0x0050, 2, 0);
}
I have a Windows Forms Application that imports and uses some C++ methods from user32.dll.
[DllImport("user32.dll")]
public static extern IntPtr WindowFromPoint(int xPoirnt, int yPoint);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(String sClassName, String sAppName);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr parentHandel, IntPtr childAfter, String sClassName, String windowTitle);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll")]
public static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
[DllImport("user32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, int nFlags);
[DllImport("msvcrt.dll")]
private static extern int memcmp(IntPtr b1, IntPtr b2, long count);
I've noticed that after my app runs for an extended period of time, the memory usage can go up to 500~MB (initial 5MB).
I don't have that much C++ experience but I know that you have to manually do memory management for C++.
My questions is, do I have to do memory management for my app or will the C# garbage collector handle it.
I have a C# wrapper for some Win32 operations involving window handles, but I am experiencing an unexpected crash, with no details, when I call a Win32 function.
Interestingly, this whole code sample works fine when the class is constructed (at application init time), but later fails when the same buildCache() method is called.
Here is the relevant code:
public delegate bool CallBack(int hWnd, int lParam);
public class Win32Interop {
private Dictionary<int, string> windowCache = new Dictionary<int, string>();
public Win32Interop() {
buildCache();
}
public void buildCache() {
windowCache.Clear();
CallBack hWndCacher = new CallBack(saveHWndHandler);
EnumWindows(hWndCacher, 0);
}
public void doThings(string title, uint message, bool rebuildCache = false) {
//Use the window title to get its handle
int hWnd = titleToHWnd(title, rebuildCache);
SendMessage(hWnd, message, 0, 0);
}
private bool saveHWndHandler(int hWnd, int lParam) {
if(IsWindow(hWnd) != 0) { / ***** CRASHES HERE ***** /
int length = GetWindowTextLength(hWnd);
StringBuilder title = new StringBuilder(length + 1);
GetWindowText(hWnd, title, title.Capacity);
string formatted = title.ToString().Trim();
windowCache.Add(hWnd, formatted);
}
return true;
}
private int titleToHWnd(string title, bool rebuildCache = false) {
if(rebuildCache)
buildCache();
if(windowCache.ContainsValue(title)) {
return windowCache.FirstOrDefault(x => x.Value.Contains(title)).Key;
} else {
throw new KeyNotFoundException(string.Format("\"{0}\" is not a window title which is available in the cache.", title));
}
}
#region Win32 API Functions
[DllImport("user32.dll")]
private static extern int EnumWindows(CallBack lpEnumFunc, int lParam);
[DllImport("user32.dll")]
private static extern int GetWindowText(int hWnd, StringBuilder lpString, int maxCount);
[DllImport("user32.dll")]
private static extern int GetWindowTextLength(int hWnd);
[DllImport("user32.dll")]
private static extern int IsWindow(int hWnd);
[DllImport("user32.lib")]
private static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
#endregion
}
Inside of the saveHWndHandler() method, I've marked the line were the debugger shows execution stops. Interestingly, there are usually ~300 window handles returned by EnumWindows(), and it always crashes on iteration number 45 or 46. The window handle it crashes on is a reasonable value, such as 12345.
According to MSDN, IsWindow() should return 0, if a window was not associated with the handle, not crash the thread.
Does anyone know why this is happening? There isn't a thrown exception, or any details in the Windows event log.
Thank you.
For those who don't want to figure out the buildCache() process works:
(1.) When buildCache() is called, the dictionary of <HWnd, Title> values is cleared.
(2.) The Win32 function EnumWindows() is called, which calls the saveHWndHandler() method for each window handle.
(3.) saveHWndHandler() will check if the current window handle still exists, the call another Win32 to function to get the window title from the handle.
(4.) The title and window handle are added to the dictionary.
I can't reproduce your issue, but a likely problem is that all of your P/Invoke signatures are wrong. HWND, LPARAM, and WPARAM data types need to at least be mapped to IntPtr in P/Invoke code.
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString,
int nMaxCount);
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam,
IntPtr lParam);
You'll need to change your corresponding instance method signatures and usages to match these correct signatures.
I need to show a modeless dialog in .NET 1.1. The following code works in .NET 2.0 or higher:
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetActiveWindow();
private void ShowModelessOwnedDialog()
{
IntPtr wHnd = GetActiveWindow();
NativeWindow parent = NativeWindow.FromHandle(wHnd);
MyForm f = new MyForm();
f.Show(parent);
}
The call Show(IWin32Window) was introduced in .NET 2.0. Do you know how to trick this code to work in .NET 1.1? Maybe any unmanaged call?
Here is an article from way back in 1999, showing how you call SetWindowLong to accomplish this. My condolences to you for having to use .NET version 1.
This is the way to assign an owner to a managed form in .NET 1.1. I extracted the following code from #Dave Markle answer and the Show(IWin32Window) implemantation of .NET 2.0.
private void AssignOwner()
{
AssignOwner(this, GetActiveWindow());
}
private void AssignOwner(Form f, IntPtr ownerHandle)
{
if (ownerHandle == IntPtr.Zero) return;
NativeWindow parent = NativeWindow.FromHandle(ownerHandle);
GetWindowLong(new HandleRef(f, f.Handle), -8);
SetWindowLong(new HandleRef(f, f.Handle), -8, new HandleRef(parent, ownerHandle));
}
public static IntPtr GetWindowLong(HandleRef hWnd, int nIndex)
{
if (IntPtr.Size == 4)
{
return GetWindowLong32(hWnd, nIndex);
}
return GetWindowLongPtr64(hWnd, nIndex);
}
public static IntPtr SetWindowLong(HandleRef hWnd, int nIndex, HandleRef dwNewLong)
{
if (IntPtr.Size == 4)
{
return SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
}
return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetActiveWindow();
[DllImport("user32.dll", EntryPoint = "GetWindowLong", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindowLong32(HandleRef hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Auto)]
public static extern IntPtr GetWindowLongPtr64(HandleRef hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)]
public static extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, HandleRef dwNewLong);
[DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)]
public static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, HandleRef dwNewLong);
MSDN states that after creating the window ownership cannot be transferred.
Because creating the window occurs in Form constructor, this poses a problem for you.
However Raymond Chen says:
Ownership is a concept that relates top-level windows. A top-level window can optionally have an owner, which is also specified when you call CreateWindowEx, and which you can change by a complicated mechanism described in my talk.
I assume the talk in question is from PDC 05 but I can't be certain.
Did you give SetParent a try?
static extern void SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
There is a MessageBox.Show overload taking and IWin32Window in .net 1.1
http://msdn.microsoft.com/en-us/library/aa335416(v=VS.71).aspx
public static DialogResult Show(
IWin32Window owner,
string text,
string caption,
MessageBoxButtons buttons,
MessageBoxIcon icon,
MessageBoxDefaultButton defaultButton
);
And this and example of getting an IWin2Window here
I'm trying to use SendMessage to Notepad, so that I can insert written text without making Notepad the active window.
I have done something like this in the past using SendText, but that required giving Notepad focus.
Now, first I'm retrieving the Windows handle:
Process[] processes = Process.GetProcessesByName("notepad");
Console.WriteLine(processes[0].MainWindowHandle.ToString());
I've confirmed it's the right handle for Notepad, the same shown within Windows Task Manager.
[DllImport("User32.dll", EntryPoint = "SendMessage")]
public static extern int SendMessage(int hWnd, int Msg, int wParam, int lParam);
From here, I haven't been able to get SendMessage to work in all my experimentation. Am I going in the wrong direction?
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
private void button1_Click(object sender, EventArgs e)
{
Process [] notepads=Process.GetProcessesByName("notepad");
if(notepads.Length==0)return;
if (notepads[0] != null)
{
IntPtr child= FindWindowEx(notepads[0].MainWindowHandle, new IntPtr(0), "Edit", null);
SendMessage(child, 0x000C, 0, textBox1.Text);
}
}
WM_SETTEXT=0x000c
You first have to find the child window where the text is entered. You can do this by finding the child window with the window class "Edit".
Once you have that window handle, use WM_GETTEXT to get the text which is already entered, then modify that text (e.g., add your own), then use WM_SETTEXT to send the modified text back.
using System.Diagnostics;
using System.Runtime.InteropServices;
static class Notepad
{
#region Imports
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
private static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
//this is a constant indicating the window that we want to send a text message
const int WM_SETTEXT = 0X000C;
#endregion
public static void SendText(string text)
{
Process notepad = Process.Start(#"notepad.exe");
System.Threading.Thread.Sleep(50);
IntPtr notepadTextbox = FindWindowEx(notepad.MainWindowHandle, IntPtr.Zero, "Edit", null);
SendMessage(notepadTextbox, WM_SETTEXT, 0, text);
}
}