• Как изменить некоторые методы стат. библиотеки и экспортировать оставшиеся?

    @AlexanderMi Автор вопроса
    Станислав Макаров,
    А что насчёт соглашений о вызове? У вас тут жесть в виде функции с переменным числом параметров. Есть ли уверенность, что соглашение одинаковое со стороны делфей и C?
    По идее должно быть cdelc и со стороны библиотеки, но я бы перепроверил это.


    код языка squirrel не передавался бы на компиляцию, будет это так.
    Да, там везде cdecl. Выдирание Сишного varargs это тот ещё перформанс и он на результат не влияет особо.

    Почему передача строки через макрос напрямую в callback выдает мне мусор, а передача в переменную а потом уже в callback - передается корректно?
    void wsq_returnASSquirrelDoesA(UBERCPPCB cb)
    {
        if (cb) {
            cb(_SC("gfjfgsjk,fghsgjbsnhsrjbtyhsrjktbsrktsnrtjksvrtsdrkjyjsknlrvtuknsrvtuknylsrtuynsrtyunsryuntsynlurtylnusvt\n"));
        }
    }
    void wsq_returnASSquirrelDoesB(UBERCPPCB cb)
    {
        const wchar_t* data = _SC("gfjfgsjk,fghsgjbsnhsrjbtyhsrjktbsrktsnrtjksvrtsdrkjyjsknlrvtuknsrvtuknylsrtuynsrtyunsryuntsynlurtylnusvt\n");
        if (cb) {
            cb(data);
        }
    }

    callback везде тот же, а результат разный. Функция A передает мусор, функция Б передает строку нормально.
  • Как изменить некоторые методы стат. библиотеки и экспортировать оставшиеся?

    @AlexanderMi Автор вопроса
    Не понял тут что где не так выглядит, но на всякий случай спрошу - вы всё собираете в одинаковой конфигурации? Нигде случаем нет такого, что одно дебаг, другое - релиз?

    Это никак влиять не должно априори т.к. dll это законченный продукт. И да, везде Debug.
    Единственное что может быть это то что строка теряется (чистится по завершению вызова в С++), а мой код получает указатель на мусор.

    Покажите подробно, как вы вызываете эту функцию и как определяете, что получили мусор. Не может быть так что строка куда-то испаряется. Это значит или там её вообще нет (что можно узнать по size), либо всё-таки что-то криво собрано или криво вызывается.


    Ничего не криво, это какая-то особенность плюсов...

    Все типы и функции описаны в squirrel.h, sqconfig.h и глубже смотреть не надо ни в какие заголовки и тем более реализацию, это внутрянка этого языка.
    Вот так идет вызов, библиотека грузится статично ( т.е. не через LoadLibrary, GetProcAddress):
    lVM := sq_open(1024);
        try
          sq_pushroottable(lVM);
          sq_setprintfunc(lVM, @VMPrintFunction, @VMErrorFunction);
          sqstd_seterrorhandlers(lVM);  //теперь sqstdlibaux.cpp будет вызывать VMPrintFunction и VMErrorFunction
          sqstd_register_iolib(lVM);
          sqstd_register_mathlib(lVM);
          sqstd_register_stringlib(lVM);
          sqstd_register_systemlib(lVM);
          sq_pop(lVM, 1);
          sScript := 'print("Hello World!)'; // Ошибка, строка не закончена, нет второго "
          sFile := 'buffer.nut';
          lRet := sq_compilebuffer(lVM, PSQChar(sScript), Length(sScript) * SizeOf(SQChar), PSQChar(sFile), SQTrue);
          ShowMessage(lRet.ToString);
        finally
        sq_close(lVM);
        end;


    sq_setprintfunc устанавливает коллбэки на с++ (SQPRINTFUNCTION) у меня объявлена так:
    //где Сишный SQChar*(wchar_t*) это PWideChar паскаля, объявленный под именем PSQChar
      
      SQPRINTFUNCTION = procedure(aVM: HSQUIRRELVM; aString: PSQChar) varargs cdecl;


    я специально гружу в VM строку с кодом где допущена ошибка.
    Итог немного предсказуем:
    Картинка

    63413300c4a8c708306717.png


    хотя если смотреть что делает вызов из самой С++ (приложив дебаггер к процессу):
    Картинка

    634133d9b1982175485549.png

    то видим что строка передаваемая через макрос _SC чутка длиннее и разнообразнее в плане букв.
    это sqstdaux.cpp из sqstdlib потому что я передаю ему головную боль о форматировании ошибок VM через вызов sqstd_seterrorhandlers. И уже его колбэки сами вызывают переданные в VM мои колбэки на функции вывода ошибок и печати.

    НО, если я изменю код в sqstdaux.cpp вот так:
    Картинка

    634135db5e005744917261.png


    то моё приложение прекрасно получает то что я хочу:
    Картинка

    6341367a08238703370897.png


    что это за магия?
    Именно из-за неё мне надо обернуть все что принимает-отдает строки, в свои функции.
    Чтобы завернуть возвращаемое строковое значение в const wchar_t* а то и с использованием LocalAlloc, потому что при простом использовании const wchar_t*, я не знаю кто управляет жизнью этих строк, и не утекают ли они в с++ или в delphi.
    А ещё потому что sq_setprintfunc ждет передачи sprintf из мира С или чего-то схожего, а мне не хочется заниматься извлечением с++ varargs из стэка в паскале.

    Что делает два шарпа в макросе _SC?
    #define _SC(a) L##a
    Почему
    const SQChar* data = _SC("%s line = (%d) column = (%d) : error %s\n");
        if(pf) {
            pf(v,data,sSource,line,column,sErr);
        }

    и
    if(pf) {
            pf(v,_SC("%s line = (%d) column = (%d) : error %s\n"),sSource,line,column,sErr);
        }

    дают разный результат?

    Переписывать сторонний код мне не хочется вот совсем. Потому что потом я замучаюсь его обновлять :)
    Потому родилась простая идея:
    Берем с++, создаем DLL with exports для Windows,
    собираю squirrel через cmake, копирую:
    squirrel\include\
    squirrel\CmakeBuildOut\lib\{$ConfigurationName}\

    в подпапку "squirrel" моей DLL
    подключаю squirrel.lib к своей dll.
    Ещё cmake умеет генерировать статические версии squirrel и sqstdlib в чем будет разница между squirrel.lib и squirrel_static.lib?
    Upd: ничего кроме того что увеличивает размер моей dll до +/- того что есть у squirrel.dll

    дальше есть например проблемная функция:
    SQUIRREL_API const SQChar *sq_objtostring(const HSQOBJECT *o);

    которая возвращает мне строку из вирт. машины.
    я делаю функцию:
    DLL_API const SQChar* wsq_objtostring(const HSQOBJECT *o) {
       SQChar* buff;
       const SQChar* data = sq_objtostring(o);
       const size_t needed = wcslen(data) + 1;
        buff = static_cast<SQChar*>(LocalAlloc(LMEM_FIXED, needed));
        if (buff)
            std::copy_n(data, needed, buff);
       return buff;
    }


    таким образом я точно получу данные и они не будут мусором, а память под строку я тоже освобожу через LocalFree уже на своей стороне.

    Но ведь есть и функции которые к строкам отношения не имеют и будут работать.
    SQUIRREL_API SQBool sq_objtobool(const HSQOBJECT *o);
    SQUIRREL_API SQInteger sq_objtointeger(const HSQOBJECT *o);
    SQUIRREL_API SQFloat sq_objtofloat(const HSQOBJECT *o);
    SQUIRREL_API SQUserPointer sq_objtouserpointer(const HSQOBJECT *o);
    SQUIRREL_API SQRESULT sq_getobjtypetag(const HSQOBJECT *o,SQUserPointer * typetag);
    SQUIRREL_API SQUnsignedInteger sq_getvmrefcount(HSQUIRRELVM v, const HSQOBJECT *po);

    Оборачивать их мне не надо, НО:
    Squirrel.dll которые рождается в результате деятельности cmake содержит в таблице экспорта все эти функции:
    картинка

    63414168c90be196633871.png

    Моя dll2.dll куда подключен squirrel.lib и даже прописан include "squirel.h" почему-то экспортирует только мои функции:
    картинка

    63414122ad82c699110791.png


    я не буду писать обертки для всех функций которые экспортирует Squirrel.dll(описаны в squirel.h)
    и раз уж я пишу свою DLL куда линкуется squirrel.lib то и держать параллельно оригинал и обертку мне тоже не надо. Как ре-экспортировать из моей dll то что описано в squirel.h?
  • Как изменить некоторые методы стат. библиотеки и экспортировать оставшиеся?

    @AlexanderMi Автор вопроса
    Станислав Макаров
    Кажется я нашел причину:
    Мне надо обернуть функции возвращающие строки во что-то типа такого:
    // Dll2.cpp : Defines the exported functions for the DLL.
    //
    
    #include "pch.h"
    #include "framework.h"
    #include "Dll2.h"
    #include <string>
    
    using namespace std;
    
    SQInteger wsq_getversion()
    {
        return sq_getversion();
    }
    
    char* wsq_teststrReturn()
    {
        char* str1;
        static const char* errorMsg = "Path return no points.";
        static const size_t needed = std::strlen(errorMsg) + 1;
    
        str1 = static_cast<char*>(LocalAlloc(LMEM_FIXED, needed));
        if (str1)
            std::copy_n(errorMsg, needed, str1);
        return str1;
    }
    
    wchar_t* wsq_teststrReturnW()
    {
        wchar_t* str1;
        static const wchar_t* errorMsg = L"Приятное управление памятью...";
        static const size_t needed = wcslen(errorMsg) + 1;
    
        str1 = static_cast<wchar_t*>(LocalAlloc(LMEM_FIXED, needed));
        if (str1)
            std::copy_n(errorMsg, needed, str1);
        return str1;
    }

    теперь с той стороны мне надо объявить переменную типа сходного с wchar_t*/char* и не забыть вызвать LocalFree

    Придется таким образом обернуть пару десятков функций, из сотни.
    И тут 2 новых вопроса:
    1. Почему squirrel.dll собранная в MSVS весит ~400 кб, а моя dll2 которая вроде как подключила и вобрала в себя squirrel.lib, весит на выходе 58 кб? Дебаг профиль не выключал. Вон я версию обернул в свою функцию и оно работает даже.

    2. squirrel.dll собранная в MSVS наружу вроде как выводит кучу функций типа sq_instanceof, sq_version:
    /*
    Не совсем понимаю, как именно экспортируются функции из squirrel.dll описанные как SQUIRREL_API 
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    #ifndef SQUIRREL_API
    #define SQUIRREL_API extern
    #endif
    */
    
    SQUIRREL_API SQBool sq_instanceof(HSQUIRRELVM v);
    SQUIRREL_API SQRESULT sq_tostring(HSQUIRRELVM v,SQInteger idx);
    SQUIRREL_API void sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool *b);
    SQUIRREL_API SQRESULT sq_getstringandsize(HSQUIRRELVM v,SQInteger idx,const SQChar **c,SQInteger *size);
    SQUIRREL_API SQRESULT sq_getstring(HSQUIRRELVM v,SQInteger idx,const SQChar **c);


    тут мне придется только обернуть sq_getstring и sq_getstringandsize чтобы строка в аргументе с не испарилась до того как её получит мой код)
    Можно как-то сделать так чтобы моя dll подключающая squirrel.lib автоматически экспортировала все что там есть + мои доп. функции? Или придется совершить финт ушами 100500 раз в духе:
    /*
    #ifdef DLL2_EXPORTS
    #define DLL2_API extern "C" __declspec(dllexport)
    #else
    #define DLL2_API __declspec(dllimport)
    #endif
    */
    
    DLL2_API SQBool __cdecl sq_instanceof(HSQUIRRELVM v);
    DLL2_API SQRESULT __cdecl sq_tostring(HSQUIRRELVM v, SQInteger idx);
    DLL2_API void __cdecl sq_tobool(HSQUIRRELVM v, SQInteger idx, SQBool* b);
    DLL2_API SQRESULT __cdecl sq_getstringandsize(HSQUIRRELVM v, SQInteger idx, const SQChar** c, SQInteger* size);
    DLL2_API SQRESULT __cdecl sq_getstring(HSQUIRRELVM v, SQInteger idx, const SQChar** c);
  • Как изменить некоторые методы стат. библиотеки и экспортировать оставшиеся?

    @AlexanderMi Автор вопроса
    Кроме того, эта библиотека есть в Conan Center, может проще поставить оттуда?

    Не проще, не решит мою проблему, там старые версии.

    . В вашем вопросе никак не отражено, как вы вызывали CMake и с какими параметрами. Ничего не понятно.

    CMake GUI - путь к папке исходников - есть.
    Путь куда билдить - указал.
    Configure, Generate, Open project, Build solution. Вот и все что я сделал. На выходе получена тьма obj, dll, lib и прочие... Тут никаких проблем не встречено.

    А что вы делаете вообще?

    Пытаюсь понять почему возвращаемый мне wchar_* в C++ выглядит строкой, в а приложении куда подключена dll'а, выглядит лютейшим мусором.
    Пока что из предположений то что С++ чистит память по завершении работы функции, в итоге я вижу набор иероглифов при том ни разу не того размера что имеет исходная строка.
  • Можно ли назвать это обучение?

    @AlexanderMi
    Всё нормально если вы чего-то не знаете.
    Если есть время и желание, полезайте в дебри неизведанного и познавайте дзен.
    На реальной работе может не быть ни первого ни второго, а вот третье уже будет прям должностной обязанностью.
  • Как установить переменные среды разработки из Batch-скрипта?

    @AlexanderMi Автор вопроса
    Благодарю за развернутый ответ.

    Вот мой батник:
    echo off
    
    echo Going to dev environment...
    set "VSCMD_DEBUG=10"
    call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x86 store
    
    echo LOOKING FOR GACUtil.exe....
    where regasm.exe
    
    echo LOOKING FOR RegAsm.exe....
    where regasm.exe
    
    echo going sleep after any key....
    pause


    Вот так он себя ведет:
    ANIMATIY26947f757017dba2.gif

    Когда кликаю мышкой, пытаюсь что-то вводить, но ничего нельзя делать....

    А вот какой вывод в при включении VSCMD_DEBUG
    G:\qq>echo off 
    Going to dev environment...
    [DEBUG:vcvarsall.bat] init with arguments 'x86 store'
    [DEBUG:vcvarsall.bat] Command line parse completed with values:
    [DEBUG:vcvarsall.bat] __VCVARSALL_TARGET_ARCH='x86'
    [DEBUG:vcvarsall.bat] __VCVARSALL_HOST_ARCH='x86'
    [DEBUG:vcvarsall.bat] __VCVARSALL_WINSDK=''
    [DEBUG:vcvarsall.bat] __VCVARSALL_STORE='-app_platform=UWP'
    [DEBUG:vcvarsall.bat] __VCVARSALL_HELP=''
    [DEBUG:vcvarsall.bat] __VCVARSALL_PARSE_ERROR='0'
    [DEBUG:VsDevCmd] Writing pre-initialization environment to C:\Users\Alex\AppData\Local\Temp\dd_vsdevcmd17_preinit_env.log
    [DEBUG:core\vsdevcmd_start] initializing with arguments ''
    [DEBUG:core\parse_cmd.bat] initializaing with arguments ''
    [DEBUG:VsDevCmd.bat] Found version "17.3.5"
    **********************************************************************
    ** Visual Studio 2022 Developer Command Prompt v17.3.5
    ** Copyright (c) 2022 Microsoft Corporation
    **********************************************************************
    [DEBUG:VsDevCmd.bat] calling "core\dotnet.bat"
  • Как установить переменные среды разработки из Batch-скрипта?

    @AlexanderMi Автор вопроса
    Мне нужно просто временно установить окружение где будут доступны мне нужные утилиты.
    Просто пути к ним пробовал указывать в PATH:
    SET PATH=aaa;bb;ccc;%PATH%
    ....

    но не работает,
    этим утилитам тоже много чего нужно.
    А vcvars.bat/vcvarsall.bat как раз ставит это самое окружение и утилиты доступны и работают должным образом.
  • Как установить антенну беспроводной связи?

    @AlexanderMi Автор вопроса
    Виктор, излишне в моём случае. Лес не плотный, небольшой, на достаточном удалении от дома. Прямая через чистое поле вплоть до БС, лес чутка сбоку.
    4g пробивает))

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

    @AlexanderMi
    emrx22, не уверен что это магазин гугл-хрома пропустит. Узко-направленное решение, мало полезное для остальных пользователей браузера. Если не пропустит, нужно будет каждому закидывать на ПК файлы, переключать в режим разработки и подгружать из локальной папки. Расширение своё не будет делать что-то особенное, чего нельзя сделать из того Userscript'а для уже существующего в маркетплейсе Tampermonkey. Бонусом Userscript можно расположить внутри сети (школы, университета) и таким образом оттуда все получат изменения данного скрипта.
  • Как правильно развести 200 МБит на 2 устройства?

    @AlexanderMi Автор вопроса
    Upd: один из патч-кордов изломан весь.
  • Как правильно развести 200 МБит на 2 устройства?

    @AlexanderMi Автор вопроса
    как конфиг показать?
  • Как управлять мышью на processing?

    @AlexanderMi
    Читая вопрос думаешь "Чиво...?!" Читая подробности "Хдеее??!1"
  • Есть ли польза от курсов по веб-разработке?

    @AlexanderMi
    от умения воспринимать информацию, мне хватает книги и гугла, ему нужен комикс/видео-ролик с подробным объяснением и/или даже кодом, а кому-то в довесок ко всему этому нужен ещё и какой-то чел над душой.
  • Как понять, что пора повышать зарплату?

    @AlexanderMi
    мало пройти собес, надо ещё и удержаться)) Если через пол года не уволился, значит заслужил.
  • Что более защищенней UbuntuDDE или Deepin?

    @AlexanderMi
    Хочу использовать защищенный Linux для электронных платежей и электронных кошельков.
    ....
    Планирую ноутбук использовать только для этого и не чего более.
    .....
    Можно ли устанавливать на этот линукс не теряя безопасность следующий софт?
    qTox, VKmessenger, Skype?

    Так что же вы хотите?
  • Каким образом обрабатываются объекты в ООП?

    @AlexanderMi
    Александр Мартынов,

    вы тащите линейное программирование в ООП, так нельзя.

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


    кто-то же всем рулит, пускай это будет менеджер объектов который выделяет память под новые и собственно киляет тех кто попросит об этом. В крестах память управляемая.
    Менеджер является event-emitter'ом, т.е. реализует механизм подписок на такие события:
    - начало работы > не дает заслать новую порцию данных пока предыдущая не будет сьедена.
    - создание объекта - менеджер создает объект и переводит в необходимость обработки.
    - смерть объекта - менеджер удаляет объект из памяти или делает его недоступным для обработки.
    - мутация - параметр: свойства, менеджер создает объект с указанными новыми свойствами.
    - рабочий начал работу
    - рабочий начал работу над объектом - параметры: объект
    - рабочий обработал объект (параметры: что обработал, какой вердикт и т.д.)
    - рабочий закончил работу совсем
    - конец работы (порция данных обработана)

    Кто занимается работой? Это может быть сам менеджер, а может некий рабочий поток или несколько потоков управляемый опять же менеджером (уже другим, тут уже привет совершенной иной задаче на управление очередями), которые так же является
    event-emitter'ом, имеет список запросов которые слушает:
    - обработай меня - собственно получив объект рабочий делает некую математику и дергает событие менеджера что бы тот создал нового мутанта, создал копию, кильнул этот объект, и поставил это все в очередь на обработку.
    и сам подписан на менеджера дабы уведомлять его о ходе работы.

    И собственно сам объект обработки:
    - имеет веса которые обсчитываются рабочим и он принимает некоторые решение над этим объектом.
    - имеет функцию клонирования с передачей списка свойства родственнику (соотв. выполняет вызов события "мутация").

    ничего не решает, просто существует.

    Когда завершается шаг? Когда рабочий на очередной итерации по подписчикам, увидит что счетчик ссылок на обработку = 0, уведомит менеджера об этом а тот вызовет событие "работа завершена".

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