21 August, 2009

IL calling conversion

Единственная инструкция которая позволяет вызывать native код из IL есть calli. Возникает вопрос как нужно написать прототип функции на C++ для того чтобы передать аргументы из managed кода.

Для платформы x86 требуется чтобы функция была fastcall - первые два аргумента (те что передаются через регистры ECX и EDX) совпадают, а вот те аргументы которые лежат на стеке болжны быть описаны в обратном порядке (смотри MSDN x86 calling conversion а также Microsoft specific ECMA-335 Partition II 15.5.6.1). Привожу пример:

void fastcall MyOwnCallback(int arg0, int arg1, int arg4, int arg3, int arg2);

С платформой x64 еще проще используется стандартный calling conversion (смотри MSDN x64 calling conversion).

18 August, 2009

Очередной серьезный пробел в MSDN

Как жаль, что MSDN теперь пишут так халтурно, лучше бы сделали нормальную документацию, а не переводили это дерьмо на кучу языков отличных от английского. И вот я снова вляпался: есть такая функция SetILInstrumentedCodeMap() в качестве 4-ого аргумента у которой должен быть массив COR_IL_MAP. Нигде в MSDN не сказано, что этот самый массив обязательно нужно выделать с помощью CoTaskMemAlloc(). Уродство, так как это есть существенное поведение функции, увы, не отраженное в документации.

P.S. Мне помогло разобраться только капание в Shared CLI.

30 July, 2009

Пара слов про наследование handles

Все вы наверное не раз пользовались классом System.Diagnostics.Process для запуска процессов из под .NET приложения. Но не все знают что если ProcessStartInfo.UseShellExecute установлен в false, то все handle исходного процесса наследуются дочерним, если конечно иное не указано для конкретного handle. Все вышесказанное касается в одинаковой мере и .NET Framework, и .NET Compact Framework.

P.S. Кстати, всем C++ разработчикам известная, функция fopen по умолчанию не уcтанавливает флаг _O_NOINHERIT. Начиная с Visual Studio 2005 добавлен новый параметр N, который собственно и должен выставлять этот флаг в fopen. Увы в Windows CE нет такой возможности. Более того так как lpSecurityAttributes в функции CreateFile должен быть всегда NULL, то и установить переменную bInheritHandle в SECURITY_ATTRIBUTES тоже невозможно.

14 July, 2009

Найди отличия

Есть два по сути эквивалентных фрагмента кода на C#:
a(x => b().c(x));
и
a(b().c);
В какой момент произойдет NullReferenceException для каждого из вариантов, если b() всегда возвращает null?

29 April, 2009

Swap при помощи XOR

Обмен двух переменных без использования дополнительной переменной с помощью XOR. http://en.wikipedia.org/wiki/XOR_swap_algorithm. Забавно то, что как-то до сих пор об этом не думалось.

11 April, 2009

Wildcard comparer

Все наверное писали что-то подобное на тестах при поступлении на работу. И вот свершилось, wildcard comparer реально потребовался. Особенности алгоритма: несколько следующих друг за другом * считаются одной.
bool WildcardCompare(LPCWSTR pFilter, LPCWSTR pString)
{
    while (*pString && *pFilter != L'*')
    {
        if (*pFilter != *pString && *pFilter != L'?')
            return false;
 
        ++pFilter;
        ++pString;
    }
 
    LPCWSTR pBaseFilter;
    LPCWSTR pBaseString;
 
    while (*pString)
    {
        if (*pFilter == L'*')
        {
            if (!*++pFilter)
                return true;
 
            pBaseFilter = pFilter;
            pBaseString = pString;
        }
        else if (*pFilter == *pString || *pFilter == L'?')
        {
            ++pFilter;
            ++pString;
        }
        else
        {
            pFilter = pBaseFilter;
            pString = ++pBaseString;
        }
    }
 
    while (*pFilter == L'*')
        ++pFilter;
 
    return !*pFilter;
}

03 April, 2009

Разные команды, разный подход к одной задаче

Очередная несовместимость .NET Profiling API для .NET Framework и .NET Compact Framework. Важный этап каждого приложения - это его завершение. И тут мы снова видим совершенно разное поведение. При завершении .NET Framework я не вижу ThreadDestroyed для главного thread и не наблюдаю вызовов AppDomainShutdownStarted/AppDomainShutdownFinished для appllication domain приложения. C этим в принципе можно смириться, так как есть вызов Shutdown означающий завершение приложения. С .NET Compact Framework все сложнее. Я наблюдаю завершение главного thread, после чего создается специальный thread для выгрузки application domain приложения и АСИНХРОННО по отношению как минимум к вызову AppDomainShutdownFinished вызывается Shutdown в главном thread. Что на мой взгляд есть очень серьезный bug.

25 March, 2009

Очередные косяки в .NET Profiling API

Есть такой event JITInlining который спрашивает у профайлера будем ли в функцию A инлайнить функцию B. Обычно эти event'ы возникают между JITCompilationStarted и JITCompilationFinished. Что на самом деле довольно логично: начали компиляцию, проинлайнили чего-нибудь, закончили компиляцию. Но вот, откуда ни возьмись, появляются независимые JITInlining без обрамления начала и конца компиляции. Поиследовав немного этот вопрос я нашел, что token функции в которую производятся инлайны всегда 0x06000000 - что на самом деле говорит нам, что токена у такой функции нет. Token класса такой же пустой - 0x02000000. Выводы? А их нет - это косяк, хотя и довольно безобидный.

Еще косячок посерьезнее - после event'a AppDomainShutdownStarted могут происходить компиляции finalizers в application domain для которого был вызван AppDomainShutdownStarted. С другой стороны в документации написано, что id application domain стабилен и правилен только до окончания вызова AppDomainShutdownStarted.