Сообщение Re[3]: C++/CLI утечка USER объектов от 27.05.2015 3:47
Изменено 27.05.2015 4:11 Mystic Artifact
PD>Он может там оказаться
Всё правильно.
Но, тут не PInvoke, поэтому я твои выдержки опустил, а вставлю другие из того же поста:
Именно на это я изначально и намекал, что есть какая-то магия.For managed C++ and IJW, the story is a little different. This is important for you C++ programmers out there, so I hope you're still reading! If you use DllImport explicitly in C++, the same rules apply as with C#. But when you call unmanaged APIs directly from managed C++ code, neither GetLastError nor Marshal.GetLastWin32Error will work reliably. GetLastError won't work for the same reason that a PInvoke call to it wouldn't work in C#. Marshal.GetLastWin32Error won't work because the implicit PInvoke goop emitted by the compiler doesn't set SetLastError to true. To fix this, you can use #pragma unmanaged to keep code that relies on GetLastError functionality as unmanaged code.
Теперь о магии.
Пример 1. Упрощенный.
Скрытый текст | |
| |
В этом коде: не генериться ничего сверх естественного, или это трудно увидеть (в студии).
Если полазить в CLR, то в Marshal — можной найти обычный геттер, берущий last error у потока (своего).
В Win32Exception вообще специального ничего нет.
Пример 2. Отключаем магию.
Скрытый текст | |
| |
Осталось ещё немножко разобраться, почему это GetLastWin32Error в посте — не reliable. И если он не reliable — то как оно тогда работает, и можно ли этому доверять?
Всё до безобразия просто: в JIT / vclinker встроена эвристика, и PInvoke "goop" эмитится в флагом setlasterror для kernel32 (и что там ещё сейчас вместо модно), gdi32, user32, advapi32.
PD>Он может там оказаться
Всё правильно.
Но, тут не PInvoke, поэтому я твои выдержки опустил, а вставлю другие из того же поста:
Именно на это я изначально и намекал, что есть какая-то магия.For managed C++ and IJW, the story is a little different. This is important for you C++ programmers out there, so I hope you're still reading! If you use DllImport explicitly in C++, the same rules apply as with C#. But when you call unmanaged APIs directly from managed C++ code, neither GetLastError nor Marshal.GetLastWin32Error will work reliably. GetLastError won't work for the same reason that a PInvoke call to it wouldn't work in C#. Marshal.GetLastWin32Error won't work because the implicit PInvoke goop emitted by the compiler doesn't set SetLastError to true. To fix this, you can use #pragma unmanaged to keep code that relies on GetLastError functionality as unmanaged code.
Теперь о магии.
Пример 1. Упрощенный.
Скрытый текст | |
| |
В этом коде: не генериться ничего сверх естественного, или это трудно увидеть (в студии).
Если полазить в CLR, то в Marshal — можной найти обычный геттер, берущий last error у потока (своего).
В Win32Exception вообще специального ничего нет.
Пример 2. Отключаем магию.
Скрытый текст | |
| |
Осталось ещё немножко разобраться, почему это GetLastWin32Error в посте — не reliable. И если он не reliable — то как оно тогда работает, и можно ли этому доверять?
Всё до безобразия просто: в JIT / vclinker встроена эвристика, и PInvoke "goop" эмитится в флагом setlasterror для kernel32 (и что там ещё сейчас вместо модно), gdi32, user32, advapi32.
UPD:
1. Т.е. на самом деле — пока мы попадаем в эти эвристики — можно смело использовать и это будет reliable. Пост в блоге немного устарел, а этот вопрос не освещен.
2. Компилятор всё равно генерирует делает "goops" (трамплины, hunks, transitions) тем или иным способ, но неявно. Это логично и ожидаемо.
3. И уже просто в тему — забавно, но DllImport имеет разные значения по умолчанию своих параметров (например ExactSpelling) (C# vs VB.NET).