PNG/ICO/CUR/ANI изображения в стандартных контролах VB6.

Тема в разделе "VB", создана пользователем Thetrik, 10 фев 2019.

  1. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    450

    Всем привет.

    Как известно встроенные средства Visual Basic 6.0 не поддерживают возможности работы с PNG изображениями, 32 битными иконками с альфа каналом и анимированными курсорами т.е. к примеру нельзя ипользовать Png картинку в качестве свойства Form.Picture. Я представляю небольшую библиотеку и Add-in которые позволяют обойти эти ограничения. Данная библиотека позволяет загружать и сохранять такие изображения (с альфа каналом) стандартными средствами (LoadPicture / SavePicture), а также включает поддержку таких изображений (с альфа каналом) в контролы. Любой контрол который в своей работе использует стандарнтые Ole Picture объекты будет поддерживать загрузку таких изображений. В свою очередь если изображение выводится посредством IPicture::Render то картинка будет отрисовываться с учетом альфа канала. Данная библиотека должна работать на всех версиях Windows начиная с XP:

    [​IMG]

    Как использовать?

    Библиотека может быть использована как внешняя DLL либо быть прилинкована к исполняемому файлу (только native code). Для использования в качестве Dll необходимо вызвать функцию Initialize которая вернет 1 в случае успеха. После этого можно пользоваться возможностями библиотеки. Если необходимо выгрузить библиотеку то нужно вызвать функцию CanUnloadNow которая сообщит можно ли в данный момент выгрузить библиотеку. Если библиотека готова к выгрузке функция вернет S_OK после которой нужно вызвать Uninitialize. Если функция возвращает S_FALSE то библиотеку нельзя выгружать т.к. имеются активные Picture объекты которые еще не выгружены и они используют библиотеку. Для IDE создан специальный Add-in который автоматически загружает библиотеку при старте среды. В скомпилированном варианте можно к примеру в событии Initialize или в процедуре Main вызывать Initialize, а при завершении Uninitialize:
    Код (Visual Basic):
    1. Private Declare Function Initialize Lib "VBPng.dll" () As Long
    2. Private Declare Sub Uninitialize Lib "VBPng.dll" ()
    3.  
    4. Private Sub Form_Initialize()
    5.  
    6.     If Initialize() = 0 Then
    7.         MsgBox "Unable to initialize png dll", vbCritical
    8.     End If
    9.  
    10. End Sub
    11.  
    12. Private Sub Form_Terminate()
    13.     Uninitialize
    14. End Sub
    Для статической линковки необходимо использовать более новый линкер (в своих примерах я использовал линкер из Visual Studio 2010), поскольку оригинальный имеет баги при использовании опции /OPT:REF, а также в секцию VBCompiler файла проекта (vbp) необходимо добавить параметры:
    Для EXE:
    Код (Text):
    1. LinkSwitches= ..\Libs\msvcrt_winxp.obj ..\Libs\VBPng.lib -ENTRY:mainCRTStartup
    Для DLL:
    Код (Text):
    1. LinkSwitches= ..\Libs\msvcrt_winxp.obj ..\Libs\VBPng.lib -ENTRY:VBDllMain -EXPORT:Initialize -EXPORT:Uninitialize
    В случае DLL, в скомпилированном виде необходимо сделать инициализацию, вызвав Initialize из себя же при первом запуске.

    Как это работает?

    Библиотека написана на C++. Принцип работы библиотеки основан на перехвате функций OleLoadPictureEx, OleLoadPicture и OleIconToCursor. Данные функции не поддерживают загрузку подобных изображений, поэтому если загружается PNG файл, библиотека VbPng пытается загрузить файл с помощью GDI+ или USER32 (в зависимости от типа изображения). При успехе создается аналогичный StdPicture объект который и возвращается функцией. Для вызывающей стороны все это выглядит как-будто она работает с оригинальным объектом. Сам объект поддерживает интерфейсы IPicture, IPictureDisp, IPersistStream, IConnectionPointContainer (не поддерживает connection point'ы возвращает E_NOTIMPL), IDispatch, поэтому может быть присвоен Object переменной или к примеру быть сохраненным в PropertyBag.

    Для того чтобы использовать библиотеку необходимо вызвать функцию Initialize. Данная функция инициализирует данные необходимые для функционирования модуля. Инициализируется COM, GDI+, устанавливаются перехваты и регистрируется COM-сервер изображений. Данный сервер нужен для создания объектов изображений посредством CoCreateInstance в особенности при создании изображений из PropertyBag'а или другого хранилища. Когда рантайм загружает изображения из PropertyBag'а создается объект по CLSID сохраненному в хранилище (IPersist::GetClassID), а затем выполняется инициализация посредством IPersistStream::Load.


    Перехватчик функций реализован в классе CHooker. Данный класс использует дизассемблер длин (ldasm) от Ms-Rem с небольшой доработкой. Доработка заключается в добавление флага OP_REL32 к некоторым инструкциям (к примеру JMP SHORT), поскольку в оригинале на некоторых относительных инструкциях этот флаг отсутствовал. Для перехвата функции используется простейший метод сплайсинга при котором в начало функции всталяется инструкция JMP которая переводит поток исполнения на функцию-перехватчик. Поскольку в начале оригинальной функции содержатся инструкции которые мы перезаписываем, необходимо правильно перенести инструкции для того чтобы была возможность вызвать оригинальную функцию. При вызове метода Hook с помощью дизассемблера длин определяется целое количество инструкций которое будет перезаписано инструкцией JMP (5 байт). После этого выделяется временный буфер (с разрешением на исполнение данных) в который будут скопированы данные инструкции + JMP на инструкцию следующую за перезаписываемой. Это позволит, передав управление на этот буфер, вызвать оригинальную функцию как-будто перехвата не было. Тут существует одна сложность заключающаяся в том, что мы не можем просто так скопировать инструкции, поскольку существуют относительные инструкции типа JMP, CALL, JNE которые "прыгают" относительно своего адреса. Для определения типа инструкции как раз и служит флаг OP_REL32 который показывает является ли инструкция относительной или нет. Другая сложность заключается в том что существуют "короткие" относительные инструкции которые "прыгают" в пределах 255 байт, а при переносе кода в буфер расстояние может значительно увеличится. Поэтому после определения количества перезаписываемых инструкций выделяется буфер размером как минимум чтобы обеспечить транслирование из коротких в длинные инструкции. После этого производится анализ каждой инструкции и при необходимости происходит корректировка смещения и типа. В конце буфера добавляется инструкция JMP со смещением на инструкцию следующую за последней перезаписаной. Наконец начало функции перезаписывается на безусловный JMP на функцию-перехватчик.

    CHooker объекты используют в качестве буфера кода кучу (Heap) с разрешением на исполнение, поэтому код является DEP безопасным. Куча автоматически создается при создании первого перехватчика и удаляется при уничтожении последнего. В проекте используются 3 таких объекта для перехвата 3-х функций OleLoadPictureEx, OleLoadPicture и OleIconToCursor, с соответствующим перехватчиками OleLoadPictureEx_user, OleLoadPicture_user и OleIconToCursor_user. В системах до Windows 8 (для загрузки изображений) можно было перехватывать только одну OleLoadPictureEx функцию которая вызывается из OleLoadPicture, но начиная с Windows 8 OleLoadPicture вызывает уже недокументированную OleLoadPictureExt, поэтому для обеспечения правильной работы некоторых контролов (к примеру ImageList) нужно перехватывать 2 этих функции. Конечно можно пробовать перехватывать OleLoadPictureExt, но эта функция недокументирована и не факт что в новых версиях Microsoft не изменят эту функцию на другую. В перехватчиках вызывается оригинальная функция и если вызов окончился неудачей вызывается наша реализация. Чтобы обеспечить возможность узнать был ли перехват уже осуществлен (к примеру подгруженная DLL уже перехватила и нет смысла делать это еще раз) используется переменна окружения "VBPng".

    OleIconToCursor перехватывается потому что она используется рантаймом для конвертирования иконок в курсоры. Перехватывая ее, мы получаем возможность обойти ограничения данной функции. Дело в том что эта функция не может правильно конвертировать анимированные курсоры (она конвертирует только первый кадр). Проект содержит класс CANICursors который хранит ссылки на все созданные анимированные курсоры. Когда перехватчик получает хендл иконки он пытается найти подходящий CICOPicture объект и если такой имеется, делается правильная копия анимированного курсора.

    Основа библиотеки - класс CPicture который и реализует всю логику работы изображений. Данный класс создавался на основе реверс-инжиниринга библиотеки oleaut32 некоторые функции возможно реализованы не точно. Данный класс позволяет загружать PNG изображения из COM потока (IStream), а также сохранять их в него. Библиотека ведет учет созданных объектов в глобальной переменной g_lCountOfObject для того чтобы обеспечить контроль при выгрузке библиотеки вызовом CanUnloadNow. В противном случае не было бы способа узнать можно ли выгрузить библиотеку или нет. Соответственно при выгрузке библиотеки которой пользуются активные объекты происходило бы падение.

    Загрузка изображений выполняется методом LoadFromStream. Этот метод проверяет сигнатуру загружаемого файла и на основе этой информации создает дочерний CPictureInternal объект который содержит специфичную для каждого типа изображений логику работы. Поскольку при загрузке из потока GDI+ автоматически устанавливает указатель в начало, приходится создавать поток в котором содержатся только данные файла (также данный поток нужен для обеспечения поддержки свойства KeepOriginalFormat). Данная задача выполняется формато-специфичными методами CreatePngStream/CreateIcoStream/CreateAniStream в которых также происходит валидация данных.

    Второй по важности метод - это Render. Тут все просто, происходит подготовка координат для вывода изображения в HIMETRIC и происходит вывод с помощью виртуального метода CPictureInternal::Draw. Для PNG используется AlphaBlend, для иконок - DrawIconEx. Т.к. свойство get_Attributes возвращает PICTURE_TRANSPARENT то пользователь перед выводом изображения сам заботится о восстановлении фона за изображением.

    Метод SaveAsFile сохраняет изображение в поток. Тут все тоже самое только наоборот. Также стоит отметить что если использовалось сохранение оригинального формата то данные изображение берутся из сохраненного потока. В противном случае, для PNG, создается временный GDI+ битмап из пикселей DIB-секции, извлекается CLSID PNG кодека и происходит сохранение изображения во временный поток. Далее из этого потока данные копируются в поток назначения. CICOPicture класс поддерживает сохранение только из сохраненного потока.

    Как бонус наше приложение получает полноценную 32-битную иконку:

    [​IMG]

    Следующая группа методов это реализация интерфейса IDispatch. Поскольку данные о типе IPicture хранятся в стандартной библиотеке stdole2.tlb то в методе GetTypeInfo происходит загрузка этой библиотеки с извлечением нужного интерфейса типа через ITypeLib::GetTypeInfoOfGuid. Тоже самое относится к методу GetIDsOfNames, тут просто происходит транслирование вызова стандартному ITypeInfo::GetIDsOfNames. Метод Invoke реализован напрямую с проверкой параметров.

    Для того чтобы можно было статически прилинковать библиотеку к VB6 EXE файлу необходимо инициализировать сишный рантайм передачей управления на функцию mainCRTStartup и передать управление на метку ___vbaS. Для этой цели служит файл gostartup.asm написаный на fasm'е. Для EXE файла выполняются строчки:
    Код (ASM):
    1. _main:
    2. call Initialize
    3. jmp ___vbaS
    Сишный рантайм вызывает функцию main, а она в свою очередь инициализирует библиотеку VbPng. Тут существует проблема со старым линкером, поскольку то ли из-за бага, то ли из-за чего то еще, ликер отбрасывает весь VB-шный импорт из результирующего файла при использовании опции -OPT:REF. Решается данная проблема просто - заменой линкера на современный.
    Для DLL выполняются похожие действия, только в этом случае необходимо указать в качестве точки входа _VBDllMain:
    Код (ASM):
    1. _VBDllMain:
    2.  
    3. push dword [esp + 12]
    4. push dword [esp + 12]
    5. push dword [esp + 12]
    6.  
    7. ; // Init CRT
    8. call  __DllMainCRTStartup@12
    9.  
    10. ; // Init runtime
    11. jmp ___vbaS  
    В этом случае сначала вызывается инициализации сишного рантайма, а затем происходит переход на функцию DllMain ActiveX Dll.

    Для олегчения работы в IDE был написан Add-in который автоматически загружает VbPng.dll для того чтобы было удобно работать с проектами. Для отключения библиотеки просто нужно отключить Add-in. Тут есть ньюанс, если есть активные PNG-изображения, то Add-in выгрузится, но VbPng нет, при этом покажется предупреждение. В любой момент можно будет включить Add-in, найти изображения, удалить их, и заново отключить Add-in, тогда DLL выгрузится.

    _________________________________________________________________________________

    Некоторые контролы, к примеру ListView, не будут отображать альфа канал, поскольку отрисовывают себя не методом Render, а через StretchBlt, для них premultiplied фон будет черный. Это следует иметь в виду при работе с библиотекой. Также не поддерживаются уведомления IPropertyNotifySink (при желании можно реализовать). Ресурсы в FRX файлах и скомпилированных файлах также хранятся в PNG поэтому проекты не будут открываться и работать без библиотеки. Для комфортной работы рекомендуется установить Add-in с автоматическим запуском при загрузке IDE.

    В директории содержатся также несколько примеров работы:
    • Test_EXE_Linked - демонстрация 32bpp PNG изображений на стандартных контролах с использованием статической линковки;
    • Test_EXE_Dll - тоже самое только с использованием dll;
    • Test_AXDll - ActiveX DLL библиотека с использованием PNG ресурсов на форме;
    • Test_SavePng - пример сохранения изображения посредством SavePicture;
    • SaveToPropBag - пример загрузки из PropertyBag;
    • IconsCursors - демонстрация работы с 32 битными иконками и анимированными курсорами.

    Также в директории содержатся PNG файлы, собраные мной еще давно посредством спутниковой рыбалки.

    Модуль слабо тестировался, поэтому возможны баги. Буду очень рад любым замечаниям, по мере возможности буду их исправлять.
    Всем спасибо за внимание, надеюсь модуль кому-то будет полезен.

    Проект на GitHub.

    The trick,
    2019.
     
    Последнее редактирование модератором: 13 фев 2019
    Ronin_, Mikl___ и TermoSINteZ нравится это.
  2. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    2.062
    так то VB6 и 2019 год - вещи мало совместимые друг с другом...
     
  3. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    450
    Пользуются еще люди, так-то. Да и работает это все от XP (а вообще с 98) до 10 без всяких проблем и доп. либ.
     
    Последнее редактирование: 10 фев 2019
    Ronin_ нравится это.
  4. sty

    sty Member

    Публикаций:
    0
    Регистрация:
    2 фев 2019
    Сообщения:
    50
    Rel, без обид, т.к. вы являетесь человеком, который приносит реальную пользу сайту и я часто нахожу много полезной информации в ваших постах. Но, по-моему, в данном случае вы немного поторопились с выводами и просто не знаете кто такой Thetrik. Thetrik - это же человек, который открыв какой-нибудь Hex-редактор - может написать в нем EXE-файл и он "с пол оборота" будет запускаться в системе. Я знаю много его (не знаю как правильно назвать) мини программ что ли, которые он выкладывал на форуме sources.ru. Можно поинтересоваться посмотреть. К чему я это? К тому, что если у человека руки прямые, а голова светлая - он на любом языке напишет все что хочешь.
     
    Thetrik нравится это.
  5. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    2.062
    люди могут пользоваться всем чем угодно, даже заведомо мертвыми технологиями... другое дело, зачем заставлять мертвую технологию грузить пнг в свои контролы, когда можно взять современный кросплатформенный фреймворк и юзать его (кьют в плюсах и куэмэль, киви в питоне, даваэфикс в джаве, впф/ювп в дотнете)? столько отличных вариантов, бери и юзай любой, что нравится... зачем в принципе тратить время на вб6? любишь бейсик - бери вб.нет или гамбас или повербейсик или пьюрбейсик или ксоджо...
    --- Сообщение объединено, 10 фев 2019 ---
    это канеш мега ценный скилл для современного человека, но и вы меня поймите... я человек простой, вижу вб6 - предлагаю во всем лучшую современную альтернативу... нельзя зацикливаться на мертвых технологиях, нужно постоянно развиваться...
     
  6. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    450
    Во-первых, ты забываешь о таком понятии как поддержка существующего ПО. На вб написана тонна прикладного ПО работающего и отлаженного которое нужно сопровождать, а не каждый руководитель готов платить за переписывание уже готового и хорошо работающего ПО с дополнительными тестами и т.п. По себе скажу, хотя моя работа не связана с программированием, но я часто бывал на различных предприятиях в моем городе, и куча софта написана там именно на вб6 (это видно по спецефичной иконке на окнах).
    Во-вторых, что значит мертвая технология? Основное преимущество вб6 именно в нативной поддержке COM/ActiveX, где любой класс по умолчанию является ActiveX классом, а написать многопоточный внепроцессный ActiveX сервер с межпоточной изоляцией данных - дело пары минут, а отладка конечного продукта тривиальна и проста (тут уже выразили в более развернутом виде мысль). Сможешь ли ты реализовать подобное с такой же легкостью на другом ЯП? Другой вопрос - является ли COM устаревшей технологией? Думаю нет, т.к. множество вещей в винде реализовано через COM. Да и COM очень хорошая технология, я с легкостью могу работать с объектами, хоть в разных процессах, хоть с разной разрядностью, хоть на разных машинах.
    В-третьих, ты забываешь о VBA, которыми пользуется куча народа для написания скриптов для автоматизации различных офисных задач. Им тоже переходить на дотнет?
    В-четвертых, зачем менять инструмент, если его возможностей хватает? Просто не понятен этот момент.
    Данная либа, в сущности прямого отношения к вб не имеет, поскольку работает именно с виндовой oleaut32, а написана вообще на C++ так что ее вполне можно использовать в каком угодно ЯП. Сюда я ее скорее всего опубликовал не ради того что кто-то будет пользоваться ей (насколько я понимаю тут вообще никто не юзает этот яп, хотя малвари на нем написано достаточно), а скорее в качестве примера перехвата функций (без использования хотпатча), с трансляцией инструкций в буфер (с корректировкой short инструкций).
    Да нет никакой альтернативы. По такой интеграции с COM/ActiveX - нет. По крайней мере мне не известно.
     
    Последнее редактирование: 10 фев 2019
  7. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    2.062
    существующее ПО всегда можно портировать, во многих ситуация стоимость порта сравнима со стоимостью поддержки легаси кода на морально устаревшей технологии...

    это значит, что она не развивается... никогда не будет вб7, никогда не будет более оптимизированного компилятора или интерпретатора ихнего пи-кода...

    как бы любой дотнет класс автоматически реализует IUnkown и IDispatch, достаточно просто его зарегать и он доступен через COM/DCOM... так же любой COM класс доступен из дотнет автоматически, если он реализует информацию о типах в IDispatch интерфейсе... такие COM объекты имеют полную рефлекцию в дотнет... если класс не реализует IDispatch, то его все равно можно использовать, объявив его vtable...

    VBA и VB6 - вроде разные интерпретаторы и VBA все еще развивается вместе с офисом... разве нет?

    не знаю, ради развития... чтобы делать качественный и актуальный на текущий момент софт, а не заниматься мастурбацией на неразвивающиеся технологии...

    дотнет как минимум... COM сейчас умеет кто угодно, даже питон: http://www.icodeguru.com/webserver/Python-Programming-on-Win32/ch05.htm
     
  8. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    450
    Откуда такая статистика? Куча банковский софта в США на коболе написано, никто его на дотнете не переписывает. А почему? А потому что дорого и небезопасно.

    Да ладно, 64 битный VBA как-то же работает.

    Насколько мне известно нет там никакой нативной поддержки, а все реализовано через COM Interop прослойку с конверсией типов и т.п. Невозможно даже собрать внепроцесный сервер. О какой нативной поддержке идет речь? С таким же успехом можно и в вб6 сделать к примеру thiscall поддержку вызовов через прослойку COM->thiscall враппер и говорить что там нативная поддержка работы с плюсовыми объектами. Ну и в мсдн висит предупреждение что при использовании ActiveX контролов начнутся тормоза:
    upload_2019-2-10_23-52-5.png
    В вб6 я могу просто заимплементировать интерфейс, поставить бряки на методы, и запустить его. Когда клиенты будут делать запросы, я остановлюсь на методе и могу уже в этот момент начать писать метод (не останавливая сервер), вот это нативная поддержка.

    Почти одно и тоже с той лишь разницей что поддержку вб6 прикрыли в пользу вбнет, а в офис не завезли еще дотнет. Но факт в том что та же самая технология используется и данная либа под VBA также будет работать:
    upload_2019-2-10_23-46-56.png

    Ну ради развития можно и истребителем научиться управлять на работу на нем летать, но целесообразность в этом будет? Не понимаю при чем тут высказывание о качественном и актуальном продукте, поясни. Я вроде бы написал - зачем менять инструмент, если его возможностей хватает?

    Да ну, и на ассемблере можно ком, но трудозатраты? Можно поставить эксперимент с созданием многопоточного внепроцесного ActiveX EXE сервера, к которому будут обращаться клиенты и обрабатывать его события. Я буду писать на VB6, ты на питоне. Даже без теста понятно, что в вб у меня уйдет не больше 5 минут на реализацию сервера на VB6 и клиентов на VB6/VBA.
     
    Последнее редактирование модератором: 11 фев 2019
  9. f13nd

    f13nd Active Member

    Публикаций:
    0
    Регистрация:
    22 июн 2009
    Сообщения:
    402
    Если верить википедии, вижуал басик существует почти 30 лет. Большинство заведомо живых технологий лет 5 протянут максимум, и то если повезет.
     
  10. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    2.062
    когда флеш приказал долго жить, куча игроделов, основной статьей дохода которых были флеш игры, стали потихоньку переходить на Haxe или на чистый HTML5/JS и как бы никто особо потом не жаловался...

    ну начнем с того, что VBA не может существовать вне своего хост процесса... VBA не может компилить, только интерпретировать либо сорцы, либо пи-код (который походу интерпретирует одна и таже виртуальная машина с вб6 из библиотеки msvbvm)... VBA можно заимбеддить в свое приложение, как и JScript/VBScript через COM (IActiveScript интерфейсы или чего там)... формально разработка VB6 прекратилась с Visual Studio аш 6 версии, однако VBA пилят дядьки из команды мелкомягкого офиса... в офисе 2010 вышел VBA7... так что формально VBA - отдельный продукт, который раньше базировался на VB6, который мелкомягкие давно убили...

    https://code.msdn.microsoft.com/windowsapps/CSExeCOMServer-3b1c1054

    это примерно звучит как зачем пользоваться шуруповертом, если возможностей отвертки вполне хватает...

    ну канеш, лучше тратить кучу своего времени на устаревшую допотопную технологию, пытаясь выжать из нее то, для чего она не предназначена, чем изучить что-то новое и интересное... зачем использовать современные фреймворки, которые умеют напрямую работать с пнг, когда можно написать на плюсах прослойку, похукать функции в вб6 и тд? зачем юзать языки с инлайн ассемблером, если можно грязными хаками завести его в вб6?

    LISP существует более 60 без поддержки крупной корпорации, у которой странный пунктик об обратной совместимости...
     
  11. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    450
    Причем тут флеш с играми?

    Ну так ты сообщение назад говорил, "никогда не будет более оптимизированного компилятора или интерпретатора ихнего пи-кода...". Оказывается интерпретатор то есть и платформа развивается. Формально, при наличии исходников VBA написать VB7 не проблема, т.к. они собраны из одних и тех же исходников (там же можешь прочитать и про бэкенд C2). К чему я это? К тому что VBA это продолжение уже "мертвой" технологии, о который ты говоришь.

    И это встроенная поддержка? Это вообще-то простое консольное приложение с ручной реализацией COM объектов их регистрацией и т.п. CoRegisterClassObject / CoRevokeClassObject, куча разных классов, ручной месседж памп и т.п. С таким же успехом можно и на чистом C сделать, но от этого C не станет языком с нативной поддержкой COM. Вот в вб это решается действительно нативно, создал проект ActiveX EXE, добавил класс и написал 2 метода. 1 минута делов. Среда сама создаст и идентификаторы, и автоматическую регистрацию и прокачку сообщений. Вот это нативная поддержка, а не проект с почти 600 строк кода для реализации примитивной задачи.

    Ну я надеюсь ты не пользуешься шуруповерт для ремонта телефонов?

    Уже написал для чего.

    Ну и на VB6 можно красивые фреймворки напрямую работающие с пнг юзать, новомодные контролы. В чем проблема? Нужен асм - компиль объектник и прилинковывай как в новой студии при компиляции в x64. Никто не заставляет тебя использовать то что ты не хочешь. Тут речь идет о тех кто хочет. И почему грязный хак если в итоге получается код без всяких хаков как бы парадоксально не звучало?

    Без обратной совместимости их продукты никому не нужны были бы.
    --- Сообщение объединено, 11 фев 2019 ---
    Вот просто для сравнения, тот же самый код что ты привел на C# как он будет выглядеть на VB6:

    Код (Visual Basic):
    1. Option Explicit
    2.  
    3. Private Declare Function GetCurrentProcessId Lib "kernel32" () As Long
    4.  
    5. Public Event FloatPropertyChanging(ByVal fNewValue As Single, ByRef bCancel As Boolean)
    6.  
    7. Private m_fValue    As Single
    8.  
    9. Public Property Get FloatProperty() As Single
    10.     FloatProperty = m_fValue
    11. End Property
    12. Public Property Let FloatProperty( _
    13.                     ByVal fValue As Single)
    14.     Dim bCancel As Boolean
    15.  
    16.     RaiseEvent FloatPropertyChanging(fValue, bCancel)
    17.  
    18.     If Not bCancel Then m_fValue = fValue
    19.  
    20. End Property
    21.  
    22. Public Property Get HelloWorld() As String
    23.     HelloWorld = "HelloWorld"
    24. End Property
    25.  
    26. Public Sub GetProcessThreadID(ByRef pPID As Long, ByRef pTID As Long)
    27.     pTID = App.ThreadID
    28.     pPID = GetCurrentProcessId()
    29. End Sub
    30.  
    Это против твоего с 560 строками с кучей классов и ручной реализацией всего, хотя и в вб можно также все руками делать - никто не запрещает, но кому-то видимо на шарпе проще.
     
    Последнее редактирование модератором: 11 фев 2019
  12. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    2.062
    ну при том, что люди портируют большие кодовые базы на другие языки и платформы, это вполне себе норма...

    нет, развивается вба, вб6 не развивается... и никогда не будет вб7, вба никогда не будет существовать вне хост процесса, никогда не будет иметь компилятора в нативный код и тд... если бы вб6 был бы открытым проектом, его бы наверняка уже адепты форкнули и допилили... кому то же надо было пилить клон вб6 под линуксы (гамбас)... но увы и ах, во времена вб6 мелкомягкие еще не верили в оупенсорц...

    в сишечке/плюсах надо руками реализовывать IUnknown/IDispatch для COM-классов, в дотнете это происходит автоматически, как и конвертация типов (комовские варианты и иже с ними)...

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

    люди прекрасно себе юзают Линуксы и Макосы, у которых нет такого поклонения обратной совместимости как у мелкомягких...
     
  13. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    450
    Игры? Игры на вб почти никто не пишет, а речь шла об офисном софте.

    Речь шла о технологии, а вба и вб6 - это одна технология. Я вон скинул же инфу по этому.

    Это происходит через враппер, тоже самое можно сделать и на плюсах, унаследовавшись от какого-нибудь атловского CComObject или IDispatchImpl.
    Второй момент - это то что это оболочка над дотнетовскими классами, как минимум подсчет ссылок не стыкуется с концепцией сборщика мусора, и возникают потом темы типа таких. Из-за недетерминированного времени жизни объектов непонятно когда будет освобожден ресурс и появляются всякие ReleaseComObject, FinalReleaseComObject. Это не встроенная поддержка, а костыли.

    Ну кому-то видимо проще написать полтыщи строк кода вместо 20.

    Да пусть юзают. Я думаю если бы мс не заботилась об обратной совместимости мы бы наблюдали другую картину на рынке десктопов.
     
  14. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    2.062
    хоспаде, это пример, как люди переходят с одной устаревшей технологии на современную...

    я же писал, это была одна технология в бородатые времена... вба7 (офис 2010) и выше - уже доработка, которая ничего общего, кроме корней проекта, в вб6 не имеет... никто не будет бекпортить какие-то фиксы и улучшения из вба в вб6... так что вб6 с точки зрения развития как технологии мертв...

    это происходит через интероп, но какая программисту разница, генерирует эту обвязку JIT-компилятор дотнета или AOT-компилятор вб6... в конце концов большинство моментов для программиста происходит прозрачно...

    а в вб6 что? счетчик ссылок? как он обрабатывает циклы тогда? в принципе в дотнете есть концепт IDisposable и using стейтменты, который делает освобождение ресурсов детерминистически... можно при желание обернуть в класс...

    да, это проще, чем искать и скачивать визуал студию 6 версии, а потом сидеть и разбираться в мертвой технологии..

    может быть, может быть... просто раньше Линукс на десктопах не был допилен, поэтому порог вхождения был большой... но сейчас даже моя мать в своем преклонном возрасте нормально юзает линукс минт...
     
  15. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    450
    Я тебе привел контрпример где такого не происходит по причинам о которых я писал.

    Нет, это одна технология, а именно нативная поддержка ActiveX и COM, где все играет по этим правилам, а другие заведомо запрещены. Изучая вб ты автоматом изучаешь вба и наоборот (ну и вбс). Код на вб6 без всяких переделок работает на вба. Данная либа без всяких переделок работает на вба. А вот изучение к примеру вбнет это уже изучение совершенно другой технологии. Ты вероятно путаешь технологию и инструмент, но про инструмент не было и речи, а речь шла именно о технологии.

    В том то и дело что все классы в VB являются ActiveX-классами с Automation типами, а создание других вообще не предусмотрено. А разница большая, вон привел уже пример со счетчиком ссылок и падением производительности при использовании ActiveX контролов. Ни о какой нативной поддержке как в вб речи быть не может. Тоже самое видно к примеру по проектам типа ActiveX exe.

    В COM счетчик ссылок, и соответственно и в VB счетчик ссылок. Циклы должны быть реализованы через слабые ссылки (нативно поддерживается к примеру IConnectionPoint'ы).

    Ну и как это будет выглядеть? Я видел пример с внешним вбс файлом который будет вызывать Dispose, но это такой костыль и говнокодерство что я даже не буду продолжать развивать эту ветку дискуссии. МБ ты знаешь другой пример? А мы говорим о нативной поддержке COM.

    Не проще. Заметь, я не агитирую за изучение вб6 здесь, я всего лишь привел на мой взгляд логичное умозаключение:
    "зачем менять инструмент, если его возможностей хватает?"
    А если кому-то проще полтыщи строк кода пилить, да еще почти на голом API - пожалуйста. У меня к примеру нет никакого желания делать внепроцессный сервер на шарпе или плюсах, просто потому что намного меньше усилий это займет у меня на вб.

    Ну а кому нужна ось в которой после апдейта не будет работать софт? У винды тоже не все идеально, хотя они и заботятся об совместимости, а если бы не заботились? Не знаю как на линуксе (линукс только недавно поставил для ознакомления) и макось поэтому просто поверю на слово.
     
  16. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    2.062
    да какая же она одна, если у офиса даже между разными версиями формат пикода меняется... это как есть язык Red - идейный продолжатель Rebol'а... только компилятор, а не интерпретатор, в отличии от Rebol... это что? тоже одна и таже технология? или JScript - интерпретатор, который реализован на COM'е? это тоже одна технология с VB6?
    --- Сообщение объединено, 12 фев 2019 ---
    объявляешь блок кода с using стейтмент, когда управление выходит из блока (нормально или с исключением), гарантированно будет вызван метод Dispose... достаточно удобно, формально это как defer в Go/Nim/Zig или как scope(exit) в D, или как блок with в Python и тд...
    --- Сообщение объединено, 12 фев 2019 ---
    VBS имеет нативную поддержку COM? VBA?
     
  17. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    450
    Ну во-первых, откуда такая инфа? Во-вторых, даже если и меняется что с этого? Я же написал:
    Изучение VBA - это почти тоже самое что и изучение VB6, потому что технология одна, а вот изучение VB.NET - это уже другая технология. Код с VBA будет работать и в VB6, а вот с VB.NET код не будет работать ни там ни там.

    Какой блок? Я клиент твоего COM сервера, я вызываю Release из unmanaged кода. Я говорю о сценарии когда дотнет предоставляет COM объекты.
    --- Сообщение объединено, 12 фев 2019 ---
    Да. VBS только и работает с ActiveX компонентами, которые являются COM. VBA работает и с ActiveX и с COM. Вот пример использования COM из VBA (Direct3D9):
    upload_2019-2-12_23-13-50.png
     
  18. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    2.062
    когда делаешь VBA stomping (удаление сорцов заставляет офис юзать прекомпиленный пикод в документах)... пикод, собранный одной версией офиса, не работает на другой версии офиса...

    да, но тогда как запилить внепроцессный ком-сервер на вбс и вба?

    а, в этом плане... дотнетовские ком объекты подгружают рантайм, сборщик мусора должен собрать все объекты, ассоциированные с ком-объектом, после того как счетчик ссылок IUnknown'а обнулиться... если есть параноя по этому поводу, то можно переопределить Object.Finalize и вызвать GC.Collect, но это весьма странно с точки зрения всей системы...

    если бы решения со слабыми ссылками было удобоворимыми, то в принципе не было бы сборщиков мусора, все бы решалось через автоматический подсчет ссылок...
     
  19. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    450
    И откуда инфа о том что дело именно в несовместимости пи кода? Не думаю что мс будут что-то изменять в п-коде, только что-то новое добавлять (переход от x86-x64 я не рассматриваю т.к. тут явно будут изменения). Хотя это легко проверить просто запустив отладчик на 2-х разных версиях вба.

    Ну так он и является уже внепроцессным сервером (он регистрирует инстанс в ROT и работает в отдельном процессе). Юзаешь к примеру вба в ворд, а в любом клиенте просто делаешь GetObject и присоединяешься к нему и вба. Далее через Application.Run запускаешь все что тебе нужно. Вбс не может быть внепроцессным, т.к. он in-proc, но если так хочется то можно просто через DllSurrogate сделать его внепроцессным - все это позволяет COM. За примером - любой пример работы с msscript.ocx.

    Вот именно что должен, а когда он это сделает - неизвестно (мы не контролируем этот процесс, т.к. мы клиенты). По правилам COM он должен уничтожить себя и освободить все данные после того как последняя ссылка будет освобождена. Освобождать ресурсы в Finalize - нехорошая практика, это так к слову.

    А никто не говорит что это единственно верное решение, но в большинстве случаев оно работает и уже много лет без всяких нареканий. К тому же в NET также есть слабые ссылки.
     
  20. Rel

    Rel Well-Known Member

    Публикаций:
    0
    Регистрация:
    11 дек 2008
    Сообщения:
    2.062
    https://github.com/bontchev/pcodedmp - цитаты из описания дизассемблера пи-кода:
    ну он может исполняться только в контексте определенных процессов, которые хостят VBA интерпретатор... формально совместимость с комом реализует интерпретатор, так же как и в дотнете этим занимается JIT... ты не можешь сделать из VBA или VBS динамическую библиотека, без того чтобы полностью захостить в своей библиотеки интерпретатор VBA или VBS... тогда опять же вопрос, как ты сделаешь InProcServer на чистом VBS и VBA? как ты зарегистрируешь ком объект на VBA и VBS так, чтобы он был доступен по DCOM? ну и тд...

    ну опять же чисто формально в отсутствие сборщика мусора в бейсиках ты должен использовать option explicit, закрывать все, что открыл, руками и еще и присваивать переменным Nothing, чтобы удостовериться, что счетчик ссылок уменьшился... так ли тебе важно, когда освободиться ли ком объект в текущую или в следующую милисекунду... если да, то опять же можно инициализировать принудительную сборку мусора с помощью GC.Collect... но опять же паттерны таковы, что ты вполне себе безопасно кодишь с использованьем IDisposable, а сборщик мусора подтирает за тобой всю обвязку, которую сгенерировал фреймворк и JIT... никаких существенных проблем я здесь не вижу...

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

    ими мало кто пользуется...
     
    Последнее редактирование модератором: 13 фев 2019