Есть консольное приложение, которое вызывает метод в сторонней DLL. Метод открывает новое окно с дефолтной иконкой Windows.Forms.
[DllImport("external.dll", EntryPoint = "create_driver", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto, SetLastError = true)]
internal static extern int CreateDriver([Out] out IntPtr nativeDriverHandle);
[DllImport("external.dll", EntryPoint = "show_properties", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto, SetLastError = true)]
internal static extern int ShowProperties(IntPtr nativeDriverHandle);
[STAThread]
internal static void Main(string[] args)
{
var driverHandle = IntPtr.Zero;
CreateDriver(out driverHandle);
int result = ShowProperties(driverHandle);
}
Пробовал с помощью SetWindowsHookEx (в момент создания окна по сообщению WM_CREATE) и FindWindowEx (по имени окна "Свойства") как-то выцепить handle окна, ничего не получилось.
Потом наткнулся на статью на support.microsoft, где говорится, что хуки глобальные не получится использовать. И на статью на CodeProject, где для этого пишется своя DLL на ++.
Edit: выяснил, что dll создает окно не WinForms, а Qt.
Вопрос: реально ли изменить иконку Qt-окна из ConsoleApp на c#?
1 вариант (плохой, но может кому-то понадобится):
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string className, string windowTitle);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hwnd, int message, int wParam, IntPtr lParam);
private static const string WINDOW_CLASS_NAME = "needed window class name"; //в моем случае Qt5QWindowIcon
private const int WM_SETICON = 0x80;
private const int WM_GETICON = 0x007F;
private const int ICON_SMALL = 0;
private const int ICON_BIG = 1;
internal static void Main(string[] args)
{
var driverHandle = IntPtr.Zero;
CreateDriver(out driverHandle);
bool endChangeProperty = false;
var t = new Task(() =>
{
var icon = new Icon(@"ICON_PATH\Icon.ico");
var iconHndl = icon.Handle;
while (!endChangeProperty)
{
var windowHandle = FindWindow(WINDOW_CLASS_NAME, null);
if (windowHandle != IntPtr.Zero)
{
var windowIcon = SendMessage(windowHandle, WM_GETICON, ICON_SMALL, IntPtr.Zero);
if (!iconHndl.Equals(windowIcon))
{
SendMessage(windowHandle, WM_SETICON, ICON_BIG, iconHndl);
SendMessage(windowHandle, WM_SETICON, ICON_SMALL, iconHndl);
}
}
Thread.Sleep(100);
}
});
t.Start();
var result = ShowProperties(driverHandle);
endChangeProperty = true;
t.Wait();
t.Dispose();
}
Плохой, потому что:
2 вариант:
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hwnd, int message, int wParam, IntPtr lParam);
private static const string WINDOW_CLASS_NAME = "needed window class name"; //в моем случае Qt5QWindowIcon
private const int WM_SETICON = 0x80;
private const int ICON_SMALL = 0;
private const int ICON_BIG = 1;
internal static void Main(string[] args)
{
var driverHandle = IntPtr.Zero;
CreateDriver(out driverHandle);
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Subtree, OnQtFormOpened);
var res = ShowProperties(driverHandle);
Automation.RemoveAllEventHandlers();
}
private static void OnQtFormOpened(object sender, AutomationEventArgs e)
{
var processId = Process.GetCurrentProcess().Id;
if (sender is AutomationElement ae && ae.Current.ClassName == WINDOW_CLASS_NAM && processId == ae.Current.ProcessId)
{
var iconHndl = new Icon(@"ICON_PATH\Icon.ico").Handle;
SendMessage(new IntPtr(ae.Current.NativeWindowHandle), WM_SETICON, ICON_BIG, iconHndl);
SendMessage(new IntPtr(ae.Current.NativeWindowHandle), WM_SETICON, ICON_SMALL, iconHndl);
}
}
Примечания:
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
В общем, интереса ради залез в исходники Nullable<T> и увидел вот такое:
Стоит задача : при инициализации выполняется заполнение ObservableCollection данными, где имеется трудоемкий метод
Заранее прошу прощения за невнятный заголовок, не придумал как лучше объяснить
При попытке запуска какой-либо программы через VS выдает такую ошибкуРаньше этого не было, но после обновления ОС на Mac'е началось