Портирование нативного API.

Язык Visual Basic на платформе .NET.

Модераторы: Ramzes, Sebas

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4147
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Портирование нативного API.

Сообщение Mikle » 16.01.2012 (Пн) 10:04

Портирую на .net SR2D.
Есть некоторые сомнения, правильно ли я делаю.
    1. Ф-ции объявлены с помощью "Declare Function", так мне привычнее, пробовал через "DllImport" - разницы не увидел. Есть ли разница, кроме синтаксиса?
    2. Когда во внешнюю ф-ции нужно передавать указатель, который не будет запоминаться, а будет применён ТОЛЬКО непосредственно в вызванной ф-ции, а применяю такой способ:
    Код: Выделить всё
    Marshal.UnsafeAddrOfPinnedArrayElement(Ar, 0)

    3. Когда нужен указатель на массив, который запомнится и будет применяться в дальнейшем, я блокирую массив:
    Код: Выделить всё
        GCH = GCHandle.Alloc(cBuf, GCHandleType.Pinned)
        PTR = GCH.AddrOfPinnedObject.ToInt32

    Когда указатель уже не нужен - разблокирую:
    Код: Выделить всё
        If GCH.IsAllocated Then GCH.Free()
Всё ли правильно? Ничего ли не упущено?
Так же, если не сложно, оцените стилистику в целом:
http://tuapse-mikle.narod.ru/SR2D/DPBM_NET.zip
Модуль SR2D и класс Sprite - это и есть порт для SR2D.DLL.

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: Портирование нативного API.

Сообщение FireFenix » 16.01.2012 (Пн) 17:52

Mikle писал(а):1. Ф-ции объявлены с помощью "Declare Function", так мне привычнее, пробовал через "DllImport" - разницы не увидел. Есть ли разница, кроме синтаксиса?

Где-то на форуме обсуждалось, даже с примером реверса... В итоге вроде для .NET предпочтительнее DllImport, а Declare Function типа оставлено для совместимости с VB

Mikle писал(а):2. Когда во внешнюю ф-ции нужно передавать указатель, который не будет запоминаться, а будет применён ТОЛЬКО непосредственно в вызванной ф-ции, а применяю такой способ:
Код: Выделить всё
Marshal.UnsafeAddrOfPinnedArrayElement(Ar, 0)

Если маршалится в один конец, то проще указать в параметрах функции, что параметр нужно "отмаршалить" :D

Mikle писал(а):3. Когда нужен указатель на массив, который запомнится и будет применяться в дальнейшем, я блокирую массив:
Код: Выделить всё
    GCH = GCHandle.Alloc(cBuf, GCHandleType.Pinned)
    PTR = GCH.AddrOfPinnedObject.ToInt32

Блокирование тут не много не подходит. Ты выделяешь память, которую не может контролировать GC.
Я обычно использовал Marshal.AllocHGlobal, которая возвращает сразу указатель (производительность функций не замерял)

Mikle писал(а):Когда указатель уже не нужен - разблокирую:
Код: Выделить всё
    If GCH.IsAllocated Then GCH.Free()

А здесь наверное не разблокирование, а просто освобождение памяти, т.к. GC до неё дотянутся не может, то делаем ручками.
Я делал так:
Код: Выделить всё
        Dim Pointer As IntPtr
        'Some code
        If Not Pointer = IntPtr.Zero Then Marshal.FreeHGlobal(Pointer)


Mikle писал(а):Так же, если не сложно, оцените стилистику в целом

Не помню как в 2009 студии, но в 2010 по умолчанию отступ = 4 пробелам, а в проекте по 2 :)

Код: Выделить всё
Public Enum ColChannel

При объявлении структур - желательно указывать тип, тогда в некоторых случаях можно избежать лишних приведений типов

Ну и "комментарии в коде" - лучше друзья программиста :)
Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4147
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Портирование нативного API.

Сообщение Mikle » 17.01.2012 (Вт) 9:57

FireFenix писал(а):В итоге вроде для .NET предпочтительнее DllImport, а Declare Function типа оставлено для совместимости с VB

С этим ясно, можно и на Declare сделать, как DllImport, но нужны доп. атрибуты. Тогда уж, действительно, проще сразу DllImport использовать.
FireFenix писал(а):проще указать в параметрах функции, что параметр нужно "отмаршалить"

А если этот параметр передаётся внутренней ф-ции "А", которая в свою очередь передаёт его ф-ции "Б", объявленной через DllImport, то это нужно указывать в ф-ции "А", "Б", или в обеих? "Чутьё" мне говорит, что достаточно в "Б"...
FireFenix писал(а):Блокирование тут не много не подходит. Ты выделяешь память, которую не может контролировать GC.

Память выделена заранее, я только указываю, что эту память нужно зафиксировать, или я неверно понимаю работу GCHandle.Alloc.
FireFenix писал(а):Не помню как в 2009 студии, но в 2010 по умолчанию отступ = 4 пробелам, а в проекте по 2

Насколько помню, в любой студии 4 пробела, я и в VB6 сам меняю на 2.
FireFenix писал(а):При объявлении структур - желательно указывать тип, тогда в некоторых случаях можно избежать лишних приведений типов

Я так понял, речь не о структурах, а о enumах? Разве тип не будет Integer по умолчанию?
FireFenix писал(а):Ну и "комментарии в коде" - лучше друзья программиста

Это моя вечная проблема :roll:, свой код кажется настолько понятным, что в нём нечего комментировать. Никак не могу взглянуть на него глазами другого программиста.
Но, говоря "оцените стилистику в целом", я имел ввиду несколько другое - после GWBasic на QuickBasic можно продолжать использовать GoTo, всё будет работать, но гораздо лучше освоить процедуры. После QuickBasic на VB желательно приучиться-таки использовать Option Explicit и, где нужно, ООП. Я о таких же нововведениях. Кое что я учёл - теперь вместо различных LoadFromFile, Init я переопределяю несколько вариантов конструктора - это гораздо удобнее и красивее. Может что-то ещё подобное есть?

И всплыла ещё одна проблема - на Win7 X64 не работает, пишет, что была попытка загрузки программы в неверном формате, я долго искал ошибки, но не нашёл их, потом понял, что ошибок нет, не работает даже вызов DLL, написанной на C++ с единственной ф-цией "return a+b".
Win7 не даёт вызывать из .net кода нативные DLL! Причём это не относится к API. Хотя, может, замена "Declare Function" на "DllImport" изменит ситуацию, проверю.

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: Портирование нативного API.

Сообщение FireFenix » 17.01.2012 (Вт) 15:21

Mikle писал(а):
FireFenix писал(а):проще указать в параметрах функции, что параметр нужно "отмаршалить"

А если этот параметр передаётся внутренней ф-ции "А", которая в свою очередь передаёт его ф-ции "Б", объявленной через DllImport, то это нужно указывать в ф-ции "А", "Б", или в обеих? "Чутьё" мне говорит, что достаточно в "Б"...

Если функция А в управляемой среде, передаёт функции Б в нативной среде, то бы при "декларации" функции просто указываем какие параметры и по какому соглашению приводить к требуемому виду

Mikle писал(а):
FireFenix писал(а):Блокирование тут не много не подходит. Ты выделяешь память, которую не может контролировать GC.

Память выделена заранее, я только указываю, что эту память нужно зафиксировать, или я неверно понимаю работу GCHandle.Alloc.

Память выделена в локальном пуле программы, и мы должны запросить на выделение менеджером памяти (которым большей части является GC) из пула для некоторых данных.
Если памяти нужно больше, чем есть в пуле, то GC полезет просить у системы.
Когда уже память выделена из пула, GC её передаёт в личное пользование или ставит на свой учёт, чтобы подчищать

Mikle писал(а):я переопределяю несколько вариантов конструктора - это гораздо удобнее и красивее. Может что-то ещё подобное есть?

Если строиться некоторая архитектура фреймворка или движка, то будет нагляднее если использовать namespace'ы
С точки зрения стилистики - блоки определения данных, циклы, свичи и т.д. более нагляднее если между ними хоть 1 пропущенная строка, чтобы визуально выделить блок.

Mikle писал(а):И всплыла ещё одна проблема - на Win7 X64 не работает, пишет, что была попытка загрузки программы в неверном формате, я долго искал ошибки, но не нашёл их, потом понял, что ошибок нет, не работает даже вызов DLL, написанной на C++ с единственной ф-цией "return a+b".

Наверное потому, что в x64 другое соглашение вызовов (msdn). Вроде сборка под AnyCPU должно помочь
Также у Win64 может не быть тех библиотек, которые в Win32
Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4147
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Портирование нативного API.

Сообщение Mikle » 17.01.2012 (Вт) 18:47

FireFenix писал(а):Также у Win64 может не быть тех библиотек, которые в Win32

Речь о вызове ф-ции из моей DLL, эта же ф-ция из программы на VB6 вызывается без проблем. Программа на VB.NET без вызова этой ф-ции тоже работает. Программа на VB.NET с вызовом этой ф-ции на WindowsXP работает.

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 17.01.2012 (Вт) 19:50

Mikle писал(а):Программа на VB.NET с вызовом этой ф-ции на WindowsXP работает.

x32 или x64? Может быть, дело в том, что на x64 указатели занимают 8 байт?

По поводу стилистики:
1. Я бы использовал конструкции типа
Код: Выделить всё
B = If(meBottom <= b2, meBottom, b2)
вместо
Код: Выделить всё
    If meBottom <= b2 Then
      B = meBottom
    Else
      B = b2
    End If
2. Я бы стал не использовать конструкции
Код: Выделить всё
If Running Then e.Cancel = True : Running = False
хотя на Си запятую ставлю :)

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4147
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Портирование нативного API.

Сообщение Mikle » 17.01.2012 (Вт) 22:05

Qwertiy писал(а):x32 или x64? Может быть, дело в том, что на x64 указатели занимают 8 байт?

Так из VB6 же всё работает, и из .net работает, если вызывать ТОЧНО ТАК ЖЕ какую-нибудь API-функцию.
Кроме того, ф-ции с параметрами, передаваемыми ByVal тоже не работают.
XP x32.
Поправка №1 - принял, №2 - не понял, предлагаешь разбить на строки + "End If" ?
У кого-нибудь есть Win7 x64 с установленной студией? Можете запустить из среды и посмотреть где проблема?

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 17.01.2012 (Вт) 23:01

Mikle писал(а):№2 - не понял, предлагаешь разбить на строки + "End If" ?

Ага :)

Про остальное ничего сказать не могу. Хотя возникает вопрос, совпадает ли разрядность приложения с разрядностью dll. Если нет, то это может и быть причиной проблемы.

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: Портирование нативного API.

Сообщение FireFenix » 17.01.2012 (Вт) 23:04

Поставил
Код: Выделить всё
Target FW = FW4.0
Target CPU = x86

и всё работает на WinXP x64 :)
Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

Qwertiy
Доктор VB наук
Доктор VB наук
 
Сообщения: 2753
Зарегистрирован: 26.06.2011 (Вс) 21:26

Сообщение Qwertiy » 17.01.2012 (Вт) 23:08

FireFenix писал(а):Target CPU = x86

:) А если x64?

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4147
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Портирование нативного API.

Сообщение Mikle » 18.01.2012 (Ср) 18:49

Qwertiy писал(а):возникает вопрос, совпадает ли разрядность приложения с разрядностью dll. Если нет, то это может и быть причиной проблемы.

У меня VS 2008 Express, то есть ни EXE на VB, ни DLL на C++ не могут быть 64-разрядными.
1. Этот EXE с этой DLL работает на Win32.
2. EXE на VB6 с этой DLL работает на любой системе.
3. Этот EXE, если убрать из него вызов DLL, работает на любой системе.
4. Этот EXE, если заменить вызов моей DLL на какую-нибудь API, работает на любой системе.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4147
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Портирование нативного API.

Сообщение Mikle » 18.01.2012 (Ср) 22:21

Я заменил все типы Integer на явные Int32 - не помогло.
Вот исходники EXE и DLL:
Вложения
UseDLL.zip
(104.32 Кб) Скачиваний: 177

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: Портирование нативного API.

Сообщение FireFenix » 18.01.2012 (Ср) 22:37

Я провёл тест на Win7 x64
Компилировал на VS2010 Ultimate SP1 под Win7 x86, в коде и настройках ничего не менял, кроме указанных ниже

Код: Выделить всё
Taget FW: FW2.0
Taget CPU: AsAny

Не работает (Ошибка вызова ф-ии на строке абаба)

Код: Выделить всё
Taget FW: FW2.0
Taget CPU: x64

Не работает (Ошибка вызова ф-ии на строке абаба)

Код: Выделить всё
Taget FW: FW2.0
Taget CPU: x86

Работает

Код: Выделить всё
Taget FW: FW2.0
Taget CPU: Itanium

Не работает (Не известная ошибка)

Насколько я могу судить из своих опытах на AsAny, то это больше применимо к библиотекам .NET, нежели к исполняемым файлам .NET.
Что происходит внутри - не разбирался. Скорее всего виноваты соглашения вызовов API...

P.S. Тестировал первую выложенную версию
Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4147
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Портирование нативного API.

Сообщение Mikle » 21.01.2012 (Сб) 17:23

На iXBT форуме подсказали решение:
Можно обработать .NET EXEшник утилитой CorFlags с ключиком /32BIT+

Работает. Но как быть при отладке в Win64?

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: Портирование нативного API.

Сообщение FireFenix » 21.01.2012 (Сб) 17:30

ммм, а чем тебя не устроило?
Код: Выделить всё
Taget FW: FW2.0
Taget CPU: x86
Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4147
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Портирование нативного API.

Сообщение Mikle » 21.01.2012 (Сб) 18:36

А где ты опцию "Target CPU" нашёл?

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: Портирование нативного API.

Сообщение FireFenix » 21.01.2012 (Сб) 18:43

Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4147
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Портирование нативного API.

Сообщение Mikle » 21.01.2012 (Сб) 21:32

А у меня вот:
Вложения
setting.png

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: Портирование нативного API.

Сообщение FireFenix » 22.01.2012 (Вс) 1:03

Пичалька....
А если есть во вкладке Compile вверху выпадающие списки Configuration и Platform. Попробуй там поменять на x86.
Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

1Steps
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 505
Зарегистрирован: 20.12.2006 (Ср) 0:50
Откуда: New York

Re: Портирование нативного API.

Сообщение 1Steps » 22.01.2012 (Вс) 6:58

Следуй за картинками, дальше поймешь.
Вложения
Untitled.png
Untitled1.png
Untitled2.png
Untitled3.png
Удалена за ненадобностью.

Mikle
Изобретатель велосипедов
Изобретатель велосипедов
Аватара пользователя
 
Сообщения: 4147
Зарегистрирован: 25.03.2003 (Вт) 14:02
Откуда: Туапсе

Re: Портирование нативного API.

Сообщение Mikle » 22.01.2012 (Вс) 11:13

Спасибо. Разобрался.
Только нужно было сначала в "Tools\Options" разрешить "Show all settings", а уже далее в "Configuration Manager" создать новую конфигурацию.


Вернуться в Visual Basic .NET

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 14

    TopList  
cron