Example #1
0
            private unsafe string TryMSAAMenuWorkAround(IntPtr dwItemData)
            {
                if (_hwnd == IntPtr.Zero)
                {
                    return "";
                }

                // Open that process so we can read its memory...
                using (SafeProcessHandle hProcess = new SafeProcessHandle(_hwnd))
                {
                    if (hProcess.IsInvalid)
                    {
                        return "";
                    }

                    // Treat dwItemData as an address, and try to read a MSAAMENUINFO struct from there...
                    MSAAMENUINFO msaaMenuInfo = new MSAAMENUINFO();
                    int readSize = Marshal.SizeOf(msaaMenuInfo.GetType());
                    int count;

                    if (!Misc.ReadProcessMemory(hProcess, dwItemData, new IntPtr(&msaaMenuInfo), new IntPtr(readSize), out count))
                    {
                        return "";
                    }
                    // Check signature...
                    if (msaaMenuInfo.dwMSAASignature != MSAA_MENU_SIG)
                    {
                        return "";
                    }
                    // Very large values of cchWText can lead to overflows in the length calculation below, and/or
                    // large allocations; to avoid this, bail if cchWText reports a length greater than 4k - which
                    // should be more than sufficient for any menu item.
                    if (msaaMenuInfo.cchWText > 4096)
                    {
                        return "";
                    }

                    // Work out len of UNICODE string to copy (+1 for terminating NUL)
                    readSize = (msaaMenuInfo.cchWText + 1) * sizeof(char);

                    char* text = stackalloc char[readSize];

                    // Do the copy...
                    if (Misc.ReadProcessMemory(hProcess, msaaMenuInfo.pszWText, new IntPtr(text), new IntPtr(readSize), out count))
                    {
                        string menuText = new string(text);

                        int nullTermination = menuText.IndexOf('\0');

                        if (-1 != nullTermination)
                        {
                            // We need to strip null terminated char and everything behind it from the str
                            menuText = menuText.Remove(nullTermination, readSize - nullTermination);
                        }
                        return menuText;
                    }
                }

                return "";
            }
            private bool GetStateImageMapEnt(int image, ref uint state, ref uint role)
            {
                // NOTE: This method may have issues with cross proc/cross bitness.

                IntPtr address = UnsafeNativeMethods.GetProp(_hwnd, "MSAAStateImageMapAddr");
                if (address == IntPtr.Zero)
                {
                    return false;
                }

                int numStates = unchecked((int)UnsafeNativeMethods.GetProp(_hwnd, "MSAAStateImageMapCount"));
                if (numStates == 0)
                {
                    return false;
                }

                // <= used since number is a 1-based count, iImage is a 0-based index.
                // If iImage is 0, should be at least one state.
                if (numStates <= image)
                {
                    return false;
                }

                using (SafeProcessHandle hProcess = new SafeProcessHandle(_hwnd))
                {
                    if (hProcess.IsInvalid)
                    {
                        return false;
                    }

                    MSAASTATEIMAGEMAPENT ent = new MSAASTATEIMAGEMAPENT();
                    int readSize = Marshal.SizeOf(ent.GetType());
                    int count;

                    // Adjust to image into array...
                    IntPtr pAddress = new IntPtr((long)address + (image * readSize));

                    unsafe
                    {
                        if (!Misc.ReadProcessMemory(hProcess, pAddress, new IntPtr(&ent), new IntPtr(readSize), out count))
                        {
                            return false;
                        }
                    }

                    state = (uint)ent.state;
                    role = (uint)ent.role;
                }
                return true;
            }
        // Main method.  It simply copies an unmamaged buffer to the remote process, sends the message, and then
        // copies the remote buffer back to the local unmanaged buffer.
        internal static int XSendGetIndex(IntPtr hwnd, int uMsg, IntPtr wParam, IntPtr ptrStructure, int cbSize)
        {
            using (SafeProcessHandle hProcess = new SafeProcessHandle(hwnd))
            {
                if (hProcess.IsInvalid)
                {
                    // assume that the hwnd was bad
                    throw new ElementNotAvailableException();
                }

                using (RemoteMemoryBlock rmem = new RemoteMemoryBlock(cbSize, hProcess))
                {
                    if (rmem.IsInvalid)
                    {
                        throw new OutOfMemoryException();
                    }

                    // Copy the struct to the remote process...
                    rmem.WriteTo(ptrStructure, new IntPtr(cbSize));

                    // Send the message...
                    int res = Misc.ProxySendMessageInt(hwnd, uMsg, wParam, rmem.Address);

                    // Copy returned struct back to local process...
                    rmem.ReadFrom(ptrStructure, new IntPtr(cbSize));

                    return res;
                }
            }
        }
        // Retrieves a string when the reference to a string is embedded as a field
        // within a structure. The lParam to the message is a reference to the struct
        // 
        // The parameters are: a pointer the struct and its size.
        //                     a pointer to the pointer to the string to retrieve.
        //                     the max size for the string.
        // Param "hwnd" the Window Handle
        // Param "uMsg" the Windows Message
        // Param "wParam" the Windows wParam
        // Param "lParam" a pointer to a struct allocated on the stack
        // Param "cbSize" the size of the structure
        // Param "pszText" the address of a pointer to a string located with the structure referenced by the lParam
        // Param "maxLength" the size of the string
        // Param "remoteBitness" the bitness of the pointer contained within pszText
        internal static unsafe string GetTextWithinStructureRemoteBitness(
            IntPtr hwnd, int uMsg, IntPtr wParam, IntPtr lParam, int cbSize,
            IntPtr pszText, int maxLength, ProcessorTypes remoteBitness, bool ignoreSendResult)
        {
            using (SafeProcessHandle hProcess = new SafeProcessHandle(hwnd))
            {
                if (hProcess.IsInvalid)
                {
                    // assume that the hwnd was bad
                    throw new ElementNotAvailableException();
                }

                using (RemoteMemoryBlock rmem = new RemoteMemoryBlock(cbSize + (maxLength + 1) * sizeof(char), hProcess))
                {
                    // Allocate the space for the object as well as the string
                    // Ensure proper allocation
                    if (rmem.IsInvalid)
                    {
                        return "";
                    }

                    // Force the string to be zero terminated

                    IntPtr remoteTextArea = new IntPtr((byte*)rmem.Address.ToPointer() + cbSize);
                    if (remoteBitness == ProcessorTypes.Processor32Bit)
                    {
                        // When the structure will be sent to a 32-bit process,
                        // pszText points to an int, not an IntPtr.
                        // remoteTextArea should be a 32-bit address.
                        System.Diagnostics.Debug.Assert(remoteTextArea.ToInt32() == remoteTextArea.ToInt64());
                        *(int*)((byte*)pszText.ToPointer()) = rmem.Address.ToInt32() + cbSize;
                    }
                    else
                    {
                        *(IntPtr*)((byte*)pszText.ToPointer()) = remoteTextArea;
                    }

                    // Copy the struct to the remote process...
                    rmem.WriteTo(lParam, new IntPtr(cbSize));

                    // Send the message...
                    IntPtr result = Misc.ProxySendMessage(hwnd, uMsg, wParam, rmem.Address);

                    // Nothing, early exit
                    if (!ignoreSendResult && result == IntPtr.Zero)
                    {
                        return "";
                    }

                    // Allocate the buffer for the string
                    char[] achRes = new char[maxLength + 1];

                    // Force the result string not to go past maxLength
                    achRes[maxLength] = '\0';
                    fixed (char* pchRes = achRes)
                    {
                        // Read the string from the common 
                        rmem.ReadFrom(new IntPtr((byte*)rmem.Address.ToPointer() + cbSize), new IntPtr(pchRes), new IntPtr(maxLength * sizeof(char)));

                        // Construct the returned string with an explicit length to avoid
                        // a string with an over-allocated buffer, as would occur
                        // if we simply use new string(achRes).
                        int length = 0;
                        for (; achRes[length] != 0 && length < maxLength; length++)
                        {
                        }
                        return new string(achRes, 0, length);
                    }
                }
            }
        }
        // Helper override to handle common scenario of having a string lParam
        // Handles bi-directional string marshaling
        internal static bool XSend (IntPtr hwnd, int uMsg, IntPtr wParam, ref string str, int maxLength)
        {
            using (SafeProcessHandle hProcess = new SafeProcessHandle(hwnd))
            {
                if (hProcess.IsInvalid)
                {
                    // assume that the hwnd was bad
                    throw new ElementNotAvailableException();
                }

                using (RemoteMemoryBlock rmem = new RemoteMemoryBlock(maxLength * sizeof(char), hProcess))
                {
                    if (rmem.IsInvalid)
                    {
                        return false;
                    }

                    // Send the message...
                    if (Misc.ProxySendMessage(hwnd, uMsg, wParam, rmem.Address) == IntPtr.Zero)
                    {
                        return false;
                    }

                    // Read the string from the remote buffer
                    return rmem.ReadString(out str, maxLength);
                }
            }
        }
        // Main method.  It simply copies an unmamaged buffer to the remote process, sends the message, and then
        // copies the remote buffer back to the local unmanaged buffer.
        internal static bool XSend (IntPtr hwnd, int uMsg, IntPtr ptrStructure1, IntPtr ptrStructure2, int cbSize1, int cbSize2, ErrorValue errorCode)
        {
            using (SafeProcessHandle hProcess = new SafeProcessHandle(hwnd))
            {
                if (hProcess.IsInvalid)
                {
                    // assume that the hwnd was bad
                    throw new ElementNotAvailableException();
                }

                using (RemoteMemoryBlock rmem1 = new RemoteMemoryBlock(cbSize1, hProcess))
                {
                    // Ensure proper allocation
                    if (rmem1.IsInvalid)
                    {
                        return false;
                    }

                    using (RemoteMemoryBlock rmem2 = new RemoteMemoryBlock(cbSize2, hProcess))
                    {
                        // Ensure proper allocation
                        if (rmem2.IsInvalid)
                        {
                            return false;
                        }

                        // Copy the struct to the remote process...
                        rmem1.WriteTo(ptrStructure1, new IntPtr(cbSize1));
                        rmem2.WriteTo(ptrStructure2, new IntPtr(cbSize2));

                        // Send the message...
                        IntPtr res = Misc.ProxySendMessage(hwnd, uMsg, rmem1.Address, rmem2.Address);

                        // check the result
                        if ((errorCode != ErrorValue.NoCheck) && ((errorCode == ErrorValue.Zero && res == IntPtr.Zero) || (errorCode == ErrorValue.NotZero && res != IntPtr.Zero)))
                        {
                            return false;
                        }

                        // Copy returned struct back to local process...
                        rmem1.ReadFrom(ptrStructure1, new IntPtr(cbSize1));
                        rmem2.ReadFrom(ptrStructure2, new IntPtr(cbSize2));
                    }
                }
            }

            return true;
        }
        // This method will determine if the process is running in 32-bit emulation mode on a 64-bit machine.
        private static bool IsWOW64Process(IntPtr hwnd)
        {
            using (SafeProcessHandle hProcess = new SafeProcessHandle(hwnd))
            {
                if (hProcess.IsInvalid)
                {
                    throw new Win32Exception();
                }

                // Windows XP(major version 5 and minor version 1) and above
                if (Environment.OSVersion.Version.Major > 5 || (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 1))
                {
                    try
                    {
                        // IsWow64Process() implemented in Windows XP
                        bool isWOW64Process;

                        if (!Misc.IsWow64Process(hProcess, out isWOW64Process))
                        {
                            // Function failed. Assume not running under WOW64.
                            return false;
                        }

                        return isWOW64Process;
                    }
                    catch (Win32Exception)
                    {
                        // Function failed. Assume not running under WOW64.
                        return false;
                    }
                }
                // Windows 2000 (major version 5)
                else if (Environment.OSVersion.Version.Major == 5)
                {
                    // NtQueryInformationProcess is available for use in Windows 2000 and Windows XP. 
                    // It may be altered or unavailable in subsequent versions. Applications should use the alternate functions
                    ulong infoWOW64 = 0;
                    int status = UnsafeNativeMethods.NtQueryInformationProcess(hProcess, UnsafeNativeMethods.ProcessWow64Information, ref infoWOW64, Marshal.SizeOf(typeof(ulong)), null);
                    if (NT_ERROR(status))
                    {
                        // Query failed. Assume not running under WOW64.
                        return false;
                    }
                    return infoWOW64 != 0;
                }
                // Windows 95, Windows 98, Windows Me, or Windows NT (major version 4)
                else
                {
                    // WOW64 was not available in these versions of Windows.
                    return false;
                }
            }
        }
        private static string ListView_V6_GetGroupTextOnWinXp(IntPtr hwnd, LVGROUP_64 group)
        {
            // Due to the ListView Group bug on WinXP we need to have a special implementation
            // for retrieving a text of the group for WinXP
            // On WinXP the code to give back the header text looks something like that:
            //            if (plvgrp->mask & LVGF_HEADER)
            //            {
            //                plvgrp->pszHeader = pgrp->pszHeader;
            //            }
            // Instead of something along the lines of StringCchCopy(plvgrp->pszHeader, plvgrp->cchHeader, pgrp->pszHeader);
            // Hence after the call to CommCtrl.Common_GetSetText() we will get back an internal buffer pointer
            // and not the text itself (ref string str will be ""). It makes no sense to call CommCtrl.Common_GetSetText()
            // Use XSendMessage to get the internal buffer pointer and than "manually" read the string

            // get internal buffer pointer (group.pszHeader)
            // NOTE: do no check XSendMessage.XSend since, LVM_GETGROUPINFO returns id of the group which can be 0, hence
            // can be treated as failure
            // We will check group.pszHeader to IntPtr.Zero after the call
            unsafe
            {
                XSend(hwnd, NativeMethods.LVM_GETGROUPINFO, new IntPtr(group.iGroupID), new IntPtr(&group), group.cbSize, ErrorValue.NoCheck);
            }
            if (group.pszHeader != 0)
            {
                // Read the string manually...
                // allocate memory from the unmanaged memory
                using (SafeCoTaskMem copyTo = new SafeCoTaskMem(NativeMethods.MAX_PATH))
                {
                    if (!copyTo.IsInvalid)
                    {
                        using (SafeProcessHandle hProcess = new SafeProcessHandle(hwnd))
                        {
                            if (!hProcess.IsInvalid)
                            {
                                int count;
                                if (Misc.ReadProcessMemory(hProcess, new IntPtr(group.pszHeader), copyTo, new IntPtr(NativeMethods.MAX_PATH), out count))
                                {
                                    return copyTo.GetStringAuto();
                                }
                            }
                        }
                    }
                }
            }

            return "";
        }
        // A generic GetItemText that sends a message to a control then reads memory out of the controls process.
        internal static string GetItemText(IntPtr hwnd, int msg, int index, int textLen)
        {
            if (textLen <= 0)
            {
                return "";
            }

            using (SafeProcessHandle hProcess = new SafeProcessHandle(hwnd))
            {
                if (hProcess.IsInvalid)
                {
                    // assume that the hwnd was bad
                    throw new ElementNotAvailableException();
                }

                using (RemoteMemoryBlock rmem = new RemoteMemoryBlock((textLen + 1) * sizeof(char), hProcess))
                {
                    // Allocate memory for UNICODE string.
                    if (rmem.IsInvalid)
                    {
                        return "";
                    }

                    if (Misc.ProxySendMessage(hwnd, msg, new IntPtr(index), rmem.Address) != IntPtr.Zero)
                    {
                        string itemText;

                        // Read the string from the remote buffer
                        if (rmem.ReadString(out itemText, (textLen + 1)))
                        {
                            return itemText;
                        }
                    }
                }
            }

            return "";

            //ProcessorTypes localBitness;
            //ProcessorTypes remoteBitness;
            //GetProcessTypes(hwnd, out localBitness, out remoteBitness);

            //if (localBitness == remoteBitness)
            //{
            //    return "";
            //}
            //else if (remoteBitness == ProcessorTypes.Processor32Bit)
            //{
            //ToDo: Convert from 64-bit to 32-bit
            //    return "";
            //}
            //else if (remoteBitness == ProcessorTypes.Processor64Bit)
            //{
            //ToDo: Convert from 32-bit to 64-bit
            //    return "";
            //}
            //return "";
        }
        //------------------------------------------------------
        //
        //  Generic Control Methods that support cross process / cross bitness
        //
        //------------------------------------------------------

        #region Generic Control Methods

        // A generic GetItemRect that sends a message to a control then reads memory out of the controls process.
        internal static Rect GetItemRect(IntPtr hwnd, int msg, int index)
        {
            using (SafeProcessHandle hProcess = new SafeProcessHandle(hwnd))
            {
                if (hProcess.IsInvalid)
                {
                    // assume that the hwnd was bad
                    throw new ElementNotAvailableException();
                }

                NativeMethods.Win32Rect rectW32 = NativeMethods.Win32Rect.Empty;
                int cMem = Marshal.SizeOf(rectW32.GetType());

                using (RemoteMemoryBlock remoteMem = new RemoteMemoryBlock(cMem, hProcess))
                {
                    // Check if RemoteMmeoryBlock.Allocate returns null.
                    if (remoteMem.IsInvalid)
                    {
                        return Rect.Empty;
                    }

                    unsafe
                    {
                        IntPtr localRectStart = new IntPtr(&rectW32.left);

                        remoteMem.WriteTo(localRectStart, new IntPtr(cMem));

                        if (Misc.ProxySendMessageInt(hwnd, msg, new IntPtr(index), remoteMem.Address) != 0)
                        {                            
                            remoteMem.ReadFrom(localRectStart, new IntPtr(cMem));
                            Misc.MapWindowPoints(hwnd, IntPtr.Zero, ref rectW32, 2);                            

                            // Errors in RTL handling are sometimes caused by a failure to clearly define 
                            // class responsibility for normalizing the rectangles.  If a class provides a 
                            // normalized rectangle that is subsequently normalized by a caller, Win32Rect 
                            // will convert the boundaries to EmptyRect.  This is caused by the test in 
                            // Win32Rect.IsEmpty, which returns true if (left >= right || top >= bottom).  
                            // For various reasons some controls provide normalized rectangles and some 
                            // controls do not, so the calling class needs to selectively normalize based 
                            // on known behaviors, version information, or other criteria.  
                            // CommonXSendMessage is an intermediary, consumed by multiple classes, 
                            // and normalizing here introduces some unwarranted complexity into the 
                            // responsibility contract.
                            return rectW32.ToRect(false);
                        }
                    }
                }

                return Rect.Empty;
            }

            //ProcessorTypes localBitness;
            //ProcessorTypes remoteBitness;
            //GetProcessTypes(hwnd, out localBitness, out remoteBitness);

            //if (localBitness == remoteBitness)
            //{
            //    return Rect.Empty;
            //}
            //else if (remoteBitness == ProcessorTypes.Processor32Bit)
            //{
                //ToDo: Convert from 64-bit to 32-bit
            //    return Rect.Empty;
            //}
            //else if (remoteBitness == ProcessorTypes.Processor64Bit)
            //{
                //ToDo: Convert from 32-bit to 64-bit
            //    return Rect.Empty;
            //}
            //return Rect.Empty;
        }
Example #11
0
        internal RemoteMemoryBlock(int cbSize, SafeProcessHandle processHandle) : base(true)
        {
            _processHandle = processHandle;

            SetHandle(Misc.VirtualAllocEx(_processHandle, IntPtr.Zero, new UIntPtr((uint)cbSize), UnsafeNativeMethods.MEM_COMMIT, UnsafeNativeMethods.PAGE_READWRITE));
        }