• Добро пожаловать на Форум пользователей ПО АСКОН. Пожалуйста, авторизуйтесь.
 

Уважаемые пользователи,

Хотим проинформировать вас о режиме работы регистрации на нашем сайте.

Зарегистрироваться возможно в рабочие дни, с 8:00 до 20:00 (мск).

Если у вас возникнут вопросы или потребуется дополнительная информация, не стесняйтесь обращаться к нашей службе поддержки. Вы можете связаться с нами по указанным контактным данным на нашем сайте.

Благодарим вас за понимание и сотрудничество. Мы ценим ваше терпение и стремимся предоставить вам лучший опыт использования нашего сервиса.

С уважением,
Команда Ascon

Неверное чтение строки

Автор MrBarry, 02.11.23, 08:41:15

« назад - далее »

0 Пользователи и 2 гостей просматривают эту тему.

MrBarry

Обобщая проблему из предыдущего поста, а также подобные ей, которые я встречал ранее, я понял, что она звучит так:
Любая строка, которую я передаю в Компас из своей программы, читается им как -1. Это может быть путём к файлу, строкой в основной надписи чертежа или чем угодно другим.

В С++ тип строк, который используется при взаимодействии с API Kompas это BSTR. Это можно понять по любому примеру и просто по типу данных в методах. Но я совершенно уверен, что я использую верный тип данных и верно преобразую, если и использую другую строку. Более того, даже существующие примеры от Компаса не работают, как и код Норсеева. Проблема сугубо связана с языком и/или настройками среды. Но при этом в интернете нет ничего о том, что строка вдруг становится -1, такое даже не гуглится, и я даже не знаю что думать

Среда разработки C++ Builder 11, Компас v22. Комп перезагружал, примеры запускал, тип данных менял (но кроме BSTR ничего не работает даже на стадии компиляции, что очевидно), молиться начинал...

Nipal

Привести другие строки к типу BSTR нельзя?

MrBarry

Можно, как и изначально объявить их в этом типе. Но ни то ни то не приводит к нужному результату
Функции приведения кстати даже реализованы в каждом stepX от Компаса, и они отлично работают.
Но энивей, проблема остаётся

p3452

В свое время, когда стоял выбор, отказался от C++, в том числе и из-за неудобоваримости и скудности средств для работы со строками.

MrBarry

Понимаю, но передо мной выбор в принципе не стоит, писать могу только на С++.

p.s. да и есть ли смысл в подобных сообщениях в ветке посвящённой С++? Малость напоминает атеиста, убеждающего людей в своей точке зрения в церкви :D

p3452

Цитата: MrBarry от 02.11.23, 09:38:25Малость напоминает атеиста, убеждающего людей в своей точке зрения в церкви :D

А, человек, изо дня в день, "бьющийся головой о стену" кого напоминает?

MrBarry

Упорного человека, которому нужно решить задачу

Nipal

Цитата: MrBarry от 02.11.23, 10:00:23Упорного человека, которому нужно решить задачу
Для Вас, посмотрите кидал картинку, со строками примерно также.
Разница.png

MrBarry

Цитата: Nipal от 02.11.23, 12:19:55Для Вас, посмотрите кидал картинку, со строками примерно также.
Не совсем понял что я должен был увидеть тут. Три символа, которые идут в начале первого файла, но отсутствуют во втором, в остальном они идентичны. Из-за сбитой кодировки Блокнот прочитал их как рандомные символы. В чём суть?

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

Vi2

Стандартная ошибка в С++: BSTR - это совсем не LP(C)WSTR. Да, и там, и там два байта на символ, но перед строкой BSTR стоит счётчик символов. Соответственно, просто кастить LP(C)WSTR s = L"text"; BSTR bs = (BSTR) s; нельзя. Есть нормальные классы, которые используются, чтобы передать BSTR, да и после импорта специально используется тип _bstr_t.

BSTR:
ЦитироватьA BSTR is a composite data type that consists of a length prefix, a data string, and a terminator. The following table describes these components.

Item   Description
Length prefix   A four-byte integer that contains the number of bytes in the following data string. It appears immediately before the first character of the data string. This value does not include the terminator.
Data string   A string of Unicode characters. May contain multiple embedded null characters.
Terminator   A NULL (0x0000) WCHAR.

MrBarry

Звучит очень правдоподобно
В коде я использую именно класс BSTR. Как правило, либо объявляю строку как wchar_t* str = L"string"; либо просто в функцию вставляю L"string". В качестве теста начал использовать методы TO_OLE, которые используются во всех тестовых примерах самого Компаса:
inline wchar_t * TO_OLE(wchar_t *x) { return x; }
inline wchar_t * TO_OLE(char    *x) { return WideString(x).c_bstr(); }
inline wchar_t * TO_OLE(WideString & x) { return x.c_bstr(); }

Пробовал объявлять через вторую функцию, передавая ей строку, с тем же результатом.
Как я понимаю, в целом нужно использовать не BSTR aka wchar_t*, а LPWSTR (не C, потому что функции требуют не константные строки на вход). То есть мне следует переписать строки под этот тип.
Или подходит и wchar_t*, а я неправильно объявляю строку?
Короче, спасибо за идеи, пошёл тестировать, позже отпишусь

Vi2

Вот нашёл в Сети для Билдера:

ЦитироватьПо внутреннему представлению\реализации WideString это и есть комовская BSTR (юзает виндовые ф-и SysAllocStr и т.д.) и отличается только формальной оберткой в класс

WideString represents strings of 16-bit characters.
Header
wstring.h
Description
WideString represents strings of 16-bit characters (wchar_t). As such, it is useful when working with COM. WideString values are easily converted to or from BSTR values. WideString also supports sharing the value of an existing BSTR.

Vi2

>inline wchar_t * TO_OLE(char    *x) { return WideString(x).c_bstr(); }

Вот за это руки отрывать нужно программерам, если я правильно понимаю работу класса WideString: создаётся объект из строки, возвращается указатель на строку BSTR и потом объект разрушается, т.е. указатель на строку становится неверным. Давай используй. :)

Vi2

>BSTR aka wchar_t*, а LPWSTR

BSTR строку можно передавать в функции, желающие получить LPWSTR или LPCWSTR, но обратное может (я подчёркиваю, может) привести к ошибке, потому что счётчика символов перед строкой нет, вернее, 4 байта-то есть, но там что-то несуразное и не связанное со строкой может быть, что может не приводить к ошибке, а может запросто. Ну, например, там записан -1L, который потребует при передаче выделения много гигов памяти или же чтения этих гигов в вызывающей программе. Вот кому хочется ТАК экспериментировать?!

MrBarry

Цитата: Vi2 от 03.11.23, 09:37:04создаётся объект из строки, возвращается указатель на строку BSTR и потом объект разрушается, т.е. указатель на строку становится неверным
До этого использовал этот метод и не вчитывался, а сейчас вник и понял, что действительно метод очень небезопасный. У меня он всегда работал видимо благодаря удаче и тому, что программа короткая
Цитата: Vi2 от 03.11.23, 09:43:20BSTR строку можно передавать в функции, желающие получить LPWSTR или LPCWSTR, но обратное может (я подчёркиваю, может) привести к ошибке
Что ж, методы требовали BSTR и я передавал им BSTR, тут вопросов нет.
Всё сходится на неверном объявлении строки, что у неё либо нет необходимого счётчика символов, либо наоборот в наличии лишний.

Кстати понял, что всё это время один метод успешно принимал на вход строку и обрабатывал как нужно:
kompas.ActiveInstance(TO_OLE("KOMPAS.Application.5"));Причём как в этом виде, вызывая WideString и получая оттуда BSTR, так и в виде L"String", как было раньше.
Но все остальные ситуации получением Компасом моей строки приводят к -1. Содержимое головы медленно начинает закипать...

MrBarry

Я протестировал объявление строки так, как советует справка Microsoft:
ЦитироватьThe following code is incorrect:

BSTR MyBstr = L"I am a happy BSTR";

This code builds (compiles and links) correctly, but it will not function properly because the string does not have a length prefix. If you use a debugger to examine the memory location of this variable, you will not see a four-byte length prefix preceding the data string.

Instead, use the following code:

BSTR MyBstr = SysAllocString(L"I am a happy BSTR");

Излишне говорить, что не сработало. Аналогично после того, как я протестировал вот это:
WideString(x).c_bstr()...но создавая отдельную переменную WideString, чтоб точно не потерять значение. А сама WideString вместо BSTR ожидаемо не подходит.

Vi2

ActiveInstance, скорее всего, внутренний метод класса переменной kompas, а он принимает не BSTR, а LPCWSTR или OLESTR, т.е. фактически wchar*.

Почему не работает при вызове с SysAllocString или WideString::c_bstr()? Тут скорее всего нужно иметь код перед глазами - там можно где угодно напетлять. Судя по вопросам в Сети. ;)

MrBarry

Цитата: Vi2 от 03.11.23, 17:03:12Тут скорее всего нужно иметь код перед глазами - там можно где угодно напетлять
Ну, для наглядности вот весь файл. Всё интересное, что происходит в файле, сидит в методе openLib()

Vi2

Ты вроде говорил, что перешёл на WideString, тогда почему всё ещё
   wchar_t * nameFr = TO_OLE("c:\\KompasFiles\\frag1.frw");
а не
   WideString nameFr = "c:\\KompasFiles\\frag1.frw";

PS
У меня нет определения класса WideString.

MrBarry

Функция же принимает на вход BSTR, а не WideString, нет смысла использовать его. А определения нет наверное потому что он у компилятора C++ Builder, на других его нет.
Плюс я же пробую постоянно новые варианты. Только что был L"String", потом TO_OLE, попробовал WideString, вернул обратно. Вот в последней версии снова поменял на TO_OLE. Энивей потенциально правильный вариант не такой