Здравствуйте, Alexander Shargin, Вы писали:
AS>Этой технологии скоро 15 лет стукнет. На тот момент она позволила снизить оверхед на вызовы функций в системных процессах (поток мигрирует в сервисный процесс вместе со своим стеком, где уже лежат все переданные параметры — не надо ничего копировать и т. д.).
Э... не уж то так время летит?
AS>Windows CE и Windows Mobile — это разные операционные системы, и у каждой своя нумерация. Windows Mobile использует ядро CE, но пользовательский интерфейс и набор приложений — свои собственные. А сама CE используется во встроенных системах, там где XP/Vista Embedded тяжеловаты для использования.
Ну, не знаю, не знаю. Хэл есть только на CE. Да и софт идет на обоих. Так что скорее нужно говорить о разных версиях... ответвлениях. В прочем, я пока что не очень глубоко погрузился в это дело

.
VD>>Интересно, что планируется изменить в WM7? И заведется ли он на сегодняшних девайсах?
AS>На сегодняшних девайсах — маловероятно. На девайсах ситуация вообще сложная — далеко не всегда старый девайс можно перепрошить на новую ОС, даже если аппаратно она могла бы там крутиться. Дело в том, что Windows Mobile "в чистом виде" для конечного пользователя не существует — есть лишь прошивки, в которые входит сама ось вместе с OAL, набором драйверов и т. д. Для каждого девайса прошивки свои, делают их сами производители девайсов. И так как им хочется продавать новые девайсы, выпускать новые прошивки для старых никто особо не рвётся.
Только вчера скачали и обновили прошивку для ETEN Glofish X500+. Была она на WM 6.0, стала на 6.1. Но прошивка не родная, а сделаная нашими умельцами.
Для своего HTC MAX я буквально в начале года качал новую прошивку устраняющую некоторые баги и недоработки.
Так что все не так уж страшно. Не производитель так народные умельцы сделают все что нужно

.
VD>>ОК. Попробуем. Тем более, что судя по твоим словам я все смогу сделать из дотнетного процесса, что резко упрощает задачу.
AS>Расскажи потом, что получится. Дотнет на девайсах кастрированный, иногда проблемы вылезают там, где их совершенно не ждёшь. Например, вообще нельзя загрузить в нативный процесс managed DLL (наоборот — пожалуйста).
Мои трехчасовые "приседания" привели к следующему результату.
Твои слова подтвердились. У МС как всегда бардак. Но в данном случае это немного упростило мне жизнь.
Донет в таких условиях работает, но проблемы все же есть. В одном приложении не удалось создать обычный дотнетный месэдж-луп и перехватчик сообщений окна HHTaskBar (так в CE окно таскбара называется, если кто не в курсе).
Пока что тест ограничился проверкой работоспособности самой идеи.
На сегодня я реализовал перехват WM_LBUTTONDOWN у HHTaskBar и выдачу диалога спрашивающего "Пропустить нажатие дальше?" или нет. Нажимаем "Yes" и вызывается исходная оконная процедура которая выполняет обычные действия. Если нажимаем "No", то ничего не делается. Область с кнокой [OK/x] из рассмотрения исключается, так что программы по прежнему можно закрывать без предупреждения. В первом варианте на них тоже выдавались предупреждения, но оказалось, что после потери фокуса закрытие приложений не происходит (видимо делают захват мышиного ввода который обрывается с потерей фокуса). В конечном итоге меня это не трогает, так как я не собираюсь открывать диалоги. Мне нужно всего лишь обрабатывать сдвиг пальцем вправо и влево.
Собственно исходники и бинарники можно взять здесь.
http://files.rsdn.ru/73/HHTaskBar_Subclass_Test.zip
Вроде работает, но если что софтрезет вам в помощь

.
Софтрезет так же потребуется чтобы завершить работы приложения, так как шататного выхода нет, а все испробованные мной таскменеджеры попросту не видят этого процесса (окон ведь в нем нет). Хотя можно пробовать снять приложение в то время когда открыт диалог (не уверен, что выйдет, так как он же из процесса таскбара лезть должен).
А вот и исходник (большая часть кода и времени занял импорт API, так что не очень ясно есть ли преимущество в дотнете или нет... дотнет пока что используется как безопасный С

):
using System;
using System.Linq;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
using System.Drawing;
static class Program
{
// this is the new wndproc, just show a messagebox on left button down:
private static int MyWndProc(IntPtr hWnd, int msg, int wParam, int lParam)
{
switch (msg)
{
case WM_LBUTTONDOWN:
var rc = GetWindowRect(hWnd);
var xPos = LoWord(lParam);
var yPos = HiWord(lParam);
// if click in close button...
if (xPos > rc.Width - rc.Height)
break; // do default behavior
// asc user for do default behavior
if (MessageBox.Show( "Пропустить нажатие дальше?", "Злостный перехватчик",
MessageBoxButtons.YesNo, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1) == DialogResult.Yes
)
break;
else
return 0;
default:
break;
}
return CallWindowProcCE(_oldWndProc, hWnd, msg, wParam, lParam);
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[MTAThread]
static void Main()
{
var hhTaskBar = FindWindowCE("HHTaskBar", null);
if (hhTaskBar != IntPtr.Zero)
{
_newWndProc = MyWndProc;
_oldWndProc = SetWindowLongCE(hhTaskBar, GWL_WNDPROC, _newWndProc);
MessageBox.Show(string.Format("handle is 0x{0:X} oldWndProc is 0x{1:X}",
hhTaskBar.ToInt32(),
_oldWndProc.ToInt32()));
}
Thread.Sleep(Timeout.Infinite); // kipe address space of process!!!
}
// Import of system API...
[DllImport("coredll.dll", EntryPoint = "FindWindowW", SetLastError = true)]
private static extern IntPtr FindWindowCE(string lpClassName, string lpWindowName);
[DllImport("coredll.dll", SetLastError = true, EntryPoint = "GetWindowLong")]
private static extern IntPtr GetWindowLongCE(IntPtr hWnd, int nIndex);
[DllImport("coredll.dll", SetLastError = true, EntryPoint = "SetWindowLong")]
private static extern IntPtr SetWindowLongCE(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("coredll.dll", SetLastError = true, EntryPoint = "SetWindowLong")]
private static extern IntPtr SetWindowLongCE(IntPtr hWnd, int nIndex, Win32WndProc newProc);
[DllImport("coredll.dll", EntryPoint = "CallWindowProc")]
private static extern int CallWindowProcCE(IntPtr wProc, IntPtr hWnd, int uMsg, int wParam, int lParam);
[DllImport("coredll.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
static RECT GetWindowRect(IntPtr hWnd)
{
RECT rect = new RECT();
GetWindowRect(hWnd, out rect);
return rect;
}
static int LoWord(int lParam)
{
return lParam & 0xFFFF;
}
static int HiWord(int lParam)
{
return 16 >> lParam;
}
private delegate int Win32WndProc(IntPtr hWnd, int Msg, int wParam, int lParam);
const int GWL_WNDPROC = -4;
const int WM_LBUTTONDOWN = 0x0201;
static Win32WndProc _newWndProc = null;
static IntPtr _oldWndProc = IntPtr.Zero;
}
/// <summary>Win32 RECT structure</summary>
public struct RECT
{
public RECT(int left, int top, int right, int bottom)
{
this.Left = left;
this.Top = top;
this.Right = right;
this.Bottom = bottom;
}
public RECT(System.Drawing.Point topLeft, System.Drawing.Size size)
{
this.Left = topLeft.X;
this.Top = topLeft.Y;
this.Right = topLeft.X + size.Width;
this.Bottom = topLeft.Y + size.Height;
}
public int Left;
public int Top;
public int Right;
public int Bottom;
public int Width { get { return Right - Left; } }
public int Height { get { return Bottom - Top; } }
public Size Size { get { return new Size(Width, Height); } }
public Point Location { get { return new Point(Left, Top); } }
// Handy method for converting to a System.Drawing.Rectangle
public Rectangle ToRectangle()
{ return Rectangle.FromLTRB(Left, Top, Right, Bottom); }
public static RECT FromRectangle(Rectangle rectangle)
{
return new RECT(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Bottom);
}
public override int GetHashCode()
{
return Left ^ ((Top << 13) | (Top >> 0x13))
^ ((Width << 0x1a) | (Width >> 6))
^ ((Height << 7) | (Height >> 0x19));
}
#region Operator overloads
public static implicit operator Rectangle( RECT rect )
{
return rect.ToRectangle();
}
public static implicit operator RECT( Rectangle rect )
{
return FromRectangle(rect);
}
#endregion
}