Показаны сообщения с ярлыком кодинг. Показать все сообщения
Показаны сообщения с ярлыком кодинг. Показать все сообщения

четверг, 25 июля 2024 г.

Принцип имён в API: если объект не указан явно, то действие относится к исходному объекту

Это перевод API naming principle: If there is no direct object, then the direct object is the source object. Автор: Реймонд Чен.

Обычно имена методов начинаются с глагола: widget.Toggle, widget.SetColor, widget.GetAssociatedDoodad.

Часто за глаголом следует объект: widget.SetColor, widget.GetAssociatedDoodad. Такой объект, указываемый явно — это то, над чем глагол работает, или что он создает. В примере выше: SetColor устанавливает (set) цвет (color), а GetAssociatedDoodad возвращает (get) ассоциированный doodad (associated doodad).

Иногда за глаголом вообще не следует название объекта. Например, метод widget.Toggle выше. В этом случае объект указывается неявно: это исходный объект. В приведенном выше примере widget.Toggle переключает (toggle) виджет (widget).

Всё это может показаться очевидным, но этот принцип легко упустить из виду.

понедельник, 4 декабря 2023 г.

Что такое указатель статической цепочки в контексте соглашения о вызовах ABI?

Это перевод What is a static chain pointer in the context of calling convention ABI? Автор: Реймонд Чен.

Глубоко в руководстве Application Binary Interface из System V для архитектуры AMD64 есть сноска на странице 24, в которой говорится: "%r10 используется для передачи указателя статической цепочки функции". Что такое "указатель статической цепочки"?

вторник, 21 февраля 2023 г.

Случай с загадочной ошибкой "out of bounds" из CreateUri и memmove

Это перевод The case of the mysterious "out of bounds" error from CreateUri and memmove. Автор: Реймонд Чен.

Один клиент пытался понять, почему его программа вылетала с ошибкой E_BOUNDS ("out of bounds"), возбуждаемой из вызова метода CreateUri:
combase!RoOriginateErrorW+0x50
wincorlib!Platform::Details::ReCreateFromException+0x40
contoso!`__abi_translateCurrentException'::`1'::catch$0+0x10
contoso!memmove+0x217f4
contoso!Windows::Foundation::IUriRuntimeClassFactory::CreateUri+0x44
contoso!Contoso::DashboardView::DashboardView_obj1_Bindings::Update_ViewModel_Layout_Groups+0x50
contoso!Contoso::DashboardView::DashboardView_obj1_Bindings::Update_ViewModel_Layout+0xe4
contoso!Contoso::DashboardView::DashboardView_obj1_Bindings::PropertyChanged+0x1134
contoso!XamlBindingInfo::XamlBindingTrackingBase::PropertyChanged+0x30
Судя по стеку, процедура копирования памяти memmove вызывала высокоуровневое исключение RTL C++/CX E_BOUNDS — что не имеет никакого смысла. Ещё более загадочно то, что memmove была вызвана из метода CreateUri интерфейса IUriRuntimeClassFactory, но код клиента DashboardView вообще не работает с URI. Похоже, что этот стек вызовов - это просто какая-то чепуха.

Что ж, попробуем раскрутить эту чушь.

четверг, 10 ноября 2022 г.

Почему x86-64 функции Windows НЕ начинаются с бессмысленной инструкции MOV EDI, EDI?

Это перевод Why don’t Windows functions begin with a pointless MOV EDI,EDI instruction on x86-64? Автор: Реймонд Чен.

Когда-то мы обсуждали, почему все функции Windows начинаются с бессмысленной инструкции MOV EDI, EDI. Ответ заключался в том, что эта инструкция использовалась как двухбайтовый NOP, что позволяло безопасно заменить её на инструкцию перехода JMP $-5, что позволяло применять различные исправления к работающей системе (такой метод не подходит для тех исправлений, которые изменяют структуры данных или включают взаимодействие между процессами).

Но вы могли заметить, что в 64-битной Windows эти бессмысленные инструкции исчезли. Значит ли это, что метод мёртв?

Почему все функции Windows начинаются с бессмысленной инструкции MOV EDI, EDI?

Это перевод Why do Windows functions all begin with a pointless MOV EDI, EDI instruction? Автор: Реймонд Чен.

Если вы посмотрите на ассемблерный код функций внутри DLL Windows, вы обнаружите, что они начинаются с бессмысленной инструкции MOV EDI, EDI. Эта инструкция копирует регистр в самого себя и не обновляет флаги, что совершенно не имеет смысла. Тогда зачем она там?

вторник, 24 мая 2022 г.

Как Windows определяет, должно ли вновь созданное окно использовать ориентацию LTR или RTL?

Это перевод How does Windows decide whether a newly-created window should use LTR or RTL layout? Автор: Реймонд Чен.

В Extended стилях окна можно указать, будет ли оно отображаться слева направо (Left-To-Right - LTR) или справа налево (Right To Left - RTL). Раскладка справа налево используется в языках с написанием справа налево - из которых сегодня наиболее широко используются, вероятно, арабский и иврит. Вы можете попросить Windows сделать окно с ориентацией RTL, установив Extended-стиль WS_EX_LAYOUTRTL.

пятница, 15 октября 2021 г.

Что означает поле SizeOfImage в структуре MODULEINFO?

Это перевод What does the SizeOfImage mean in the MODULEINFO structure? Автор: Реймонд Чен.

У одного клиента была программа с поддержкой плагинов, и клиент хотел провести анализ занимаемой плагинами памяти. Клиент уже умел отслеживать выделение динамической памяти плагинами (поскольку его модель плагинов была очень ограниченной), но его интересовал объём памяти, занимаемый кодом модуля и сегментами статических данных. Клиент получал информацию о плагине, вызывая функцию GetModuleInformation и просматривая поле SizeOfImage, но ему нужна была помощь в интерпретации этого значения. Будет ли SizeOfImage учитывать, например, большой статический массив с инициализацией нулями? Клиент знал, что обнулённые статические данные обычно не занимают места в самом файле, но добавляются ли они в SizeOfImage? И вообще, SizeOfImage - это размер чего именно?

вторник, 17 ноября 2020 г.

Почему в выводе echo командной строки с перенаправлением появляется 1? Кто вставляет эти единицы?

Это перевод Why does my command line redirection echo with an extra 1? Who’s inserting these rogue 1s everywhere? Автор: Реймонд Чен.

Если вы оставите включённым режим echo в командном файле, и командный файл выполняет команду с перенаправлением, тогда в выводе появится загадочная единичка.

среда, 2 сентября 2020 г.

Чему может быть равно свойство Status у WMI класса Win32_ComputerSystem?

Это перевод What are the possible Status values for Win32_ComputerSystem? Автор: Реймонд Чен.

Документация для WMI класса Win32_Computer­System содержит такое описание свойства Status:
Status
Тип данных: string
Доступ: только чтение
Квалификаторы: MaxLen (10), DisplayName (“Status”)

Текущее состояние объекта. Могут быть определены различные рабочие и нерабочие состояния. К рабочим статусам относятся: OK, Degraded и Pred Fail. Последнее значение может использоваться, к примеру, жёстким диском с поддержкой SMART, который может функционировать правильно, но прогнозирует сбой в ближайшем будущем. К нерабочим состояниям относятся: Error, Starting, Stopping и Service, которые могут применяться во время переноса зеркала диска, перезагрузки списка разрешений пользователей или другой административной работы.

Это свойство наследуется от CIM_Managed­System­Element.

Значения могут быть следующими:
OK (“OK”)
Error (“Error”)
Degraded (“Degraded”)
Unknown (“Unknown”)
Pred Fail (“Pred Fail”)
Starting (“Starting”)
Stopping (“Stopping”)
Service (“Service”)
Stressed (“Stressed”)
NonRecover (“NonRecover”)
No Contact (“No Contact”)
Lost Comm (“Lost Comm”)
Что эта чушь пытается нам сказать? И что она говорит нам о возможных значениях свойства Status для Win32_Computer­System?

пятница, 21 августа 2020 г.

Об использовании FILE_FLAG_WRITE_THROUGH и FILE_FLAG_NO_BUFFERING для проецируемых в память файлов

Это перевод On using FILE_FLAG_WRITE_THROUGH and FILE_FLAG_NO_BUFFERING for memory-mapped files. Автор: Реймонд Чен.

Клиент хотел использовать флаги FILE_FLAG_WRITE_THROUGH и FILE_FLAG_NO_BUFFERING для проецируемого в память файла (memory-mapped file), основываясь на этом руководстве в документации для функции CreateFile:
По этой причине флаг FILE_FLAG_WRITE_THROUGH часто используется совместно с флагом FILE_FLAG_NO_BUFFERING в качестве замены для вызова функции FlushFileBuffers после каждой записи, что может привести к ненужным потерям производительности. Совместное использование этих флагов позволяет избежать штрафов.
Клиент был обеспокоен тем, повлияет ли такая комбинация флагов на согласованность данных.

суббота, 23 мая 2020 г.

Дело о SHGetFolderPath(CSIDL_COMMON_DOCUMENTS), возвращающей ERROR_PATH_NOT_FOUND

Это перевод The case of the SHGetFolderPath(CSIDL_COMMON_DOCUMENTS) that returned ERROR_PATH_NOT_FOUND. Автор: Реймонд Чен.

У клиента возникла проблема с функцией SHGetFolderPath. В частности, у них была программа, которая вызывала функцию так:
SHGetFolderPath(0, CSIDL_COMMON_DOCUMENTS, 0, SHGFP_TYPE_CURRENT, PChar(pathBuffer));
но вызов функции возвращал ошибку $80070003 - это HRESULT-версия для ERROR_PATH_NOT_FOUND. Ошибка возникает только при запуске из Jenkins pipeline. Если же программа запускается автономно, то функция завершается успешно и возвращает ожидаемый результат.

пятница, 17 января 2020 г.

Подводный камень: размещение окна под TopMost окном сделает окно TopMost

Это перевод Nasty gotcha: Positioning your window beneath a topmost window makes it topmost. Автор: Реймонд Чен.

У функции DeferWindowPos (и, следовательно, любой функции на её основе, типа SetWindowPos) есть неприятный подводный камень: если вы укажете hwndInsertAfter, а окно insert-after будет самым верхним (TopMost), то позиционируемое окно будет размещено сразу после этого окна.

Пока всё идёт нормально.

Почему я не могу переместить FOLDERID_LocalAppData с помощью SHSetKnownFolderPath?

Это перевод Why can’t I use SHSetKnownFolderPath to change the location of FOLDERID_LocalAppData? Автор: Реймонд Чен.

Заказчик заметил, что его модульный тест начал давать сбой в Windows 10 версии 1803. В частности, он не прошел здесь:
SHSetKnownFolderPath(FOLDERID_LocalAppData, 0, 0, temporaryDirectory);
с ошибкой E_INVALIDARG. Что изменилось в Windows 10 версии 1803, из-за чего этот вызов стал недействительным?

четверг, 16 января 2020 г.

Почему последний выбранный файл появляется первым, когда я выбираю несколько файлов в диалоге открытия файла?

Это перевод When I select multiple files in the File Open dialog, why does the last item come first? Автор: Реймонд Чен.

Если у вас есть диалог открытия файла, который поддерживает множественный выбор, и вы выбираете несколько файлов, вы можете заметить, что файл, выбранный последним, указывается первым. Это раздражает, если порядок файлов при выборе является важным (прим. пер.: например, при добавлении фото в альбом). Почему последний выбранный элемент становится первым в списке?

понедельник, 9 сентября 2019 г.

Суеверие: почему старожилы предпочитают GetFileAttributes для проверки существования файла?

Это перевод Superstition: Why is GetFileAttributes the way old-timers test file existence? Автор: Реймонд Чен.

Если вы спросите старого пердуна: "Как проверить наличие файла?", он наверняка ответит: "Используй GetFileAttributes". Это и сегодня, вероятно, самый быстрый способ проверки существования файла, поскольку он требует только одного вызова. Другие методы (такие как FindFirstFile или CreateFile) требуют дополнительного вызова FindClose или CloseHandle - что приведёт к дополнительным запросам по сети, увеличивая стоимость проверки.

Но в прежние времена выбор GetFileAttributes был не просто оптимизацией производительности. Если вместо этого вы попытаетесь открыть файл для проверки его существования, вы можете и вовсе получить неправильный ответ!

четверг, 5 сентября 2019 г.

Что такое __wchar_t (с двумя ведущими подчёркиваниями) и почему у меня вылезают связанные с ним ошибки?

Это перевод What is __wchar_t (with the leading double underscores) and why am I getting errors about it? Автор: Реймонд Чен.

Компилятор Microsoft Visual C++ имеет параметр компилятора с названием /Zc:wchar_t, который позволяет вам контролировать, что же означает тип wchar_t.

Согласно стандарту C++, wchar_t - это отдельный родной (встроенный, нативный) тип, и именно так по умолчанию считает компилятор Visual C++. Тем не менее, вы можете передать /Zc:wchar_t-, и это отключит встроенное определение типа wchar_t, позволяя вам определить тип так, как вам нравится. А для Windows это исторически означает:
typedef unsigned short wchar_t;
потому что Windows предшествует версиям стандартов C и C++, которые представили wchar_t как собственный тип.

Так что теперь у вас есть проблема, если вы пишете библиотеку, которая будет использоваться как кодом старой школы, написанным с wchar_t, определённым как псевдоним для unsigned short, так и кодом новой школы, написанным с wchar_t как отдельным внутренним типом. Какой тип данных вам нужно использовать для строковых параметров?

Обновлено: Если FlushInstructionCache ничего не делает, почему я должен её вызывать?

Это перевод If FlushInstructionCache doesn’t do anything, why do you have to call it, revisited. Автор: Реймонд Чен.

Предполагается, что вы будете вызывать функцию FlushInstructionCache, когда вы генерируете или модифицируете исполняемый код в run-time - чтобы процессор при выполнении вашего сгенерированного/модифицированного кода читал бы написанные вами инструкции, а не старые инструкции, которые могут остаться в кеше команд процессора.

Ранее мы узнали, что в Windows 95 функция FlushInstructionCache не делает ничего, кроме возврата. Это потому, что простого вызова функции было достаточно, чтобы очистить кэш команд.

Но в Windows NT функция FlushInstructionCache выполняет реальную работу, поскольку ей необходимо уведомить все остальные процессоры о необходимости очищать их кэши.

Однако если вы посмотрите на Windows 10, то вы обнаружите, что функция FlushInstructionCache выглядит как версия для Windows 95: она ничего не делает.

В чём тут дело?

пятница, 5 апреля 2019 г.

Почему попытка остановить мою службу возвращает ERROR_BROKEN_PIPE?

Это перевод What does it mean when my attempt to stop a Windows NT service fails with ERROR_BROKEN_PIPE? Автор: Реймонд Чен.

Один клиент сообщил, что иногда у них возникает проблема: в состав их программного продукта входит служба Windows NT, и когда их клиентская программа пытается остановить службу, то иногда происходит сбой с ошибкой ERROR_BROKEN_PIPE. Их клиентская программа написана на C#, поэтому для остановки службы используется метод ServiceController.Stop, а об ошибке сообщается в форме исключения. В Win32 же это эквивалентно вызову функции ControlService с кодом SERVICE_CONTROL_STOP.

При каких условиях попытка остановить службу может привести к ошибке ERROR_BROKEN_PIPE?

понедельник, 21 января 2019 г.

Почему компилятор генерирует операции с памятью для полной переменной, даже если задействован только один байт?

Это перевод Why does the compiler generate memory operations on the full variable even though only one byte is involved? Автор: Реймонд Чен.

Когда-то я помогал с генерацией кода JIT компиляторе, и я заметил одну вещь: когда компилятору нужно было, скажем, установить старший бит в четырёхбайтовой переменной, он сделал так:
xor dword ptr [variable], 80000000h
вместо более компактного:
xor byte ptr [variable + 3], 80h
Эти две операции функционально эквивалентны: установка верхнего бита в четырёхбайтовом значении эквивалентна установке верхнего бита в однобайтовом значении - потому что младшие биты не зависят от операции.