Имя: Пароль:
1C
1С v8
Работа 1С в внешними COM-объектами
0 SpellKeeper
 
07.04.15
12:10
Добрый день, коллеги.

Пытаюсь прикрутить к 1С некую внешнюю DLL.
В этой DLL есть метод, который в качестве входного параметра требует значение типа Целое 64. Я так понимаю, что это Integer 64.
Как известно, в 1С есть только тип Число разной длины.
При попытке передачи переменной 1С в этот метод возвращается ошибка типа "Плохой тип переменной".
Как я понимаю,1С конвертирует тип Число во что-то эдакое, что не понимает COm-объект.
Вообще, значение, которое я пытаюсь передавать - это некий ИД записи из другой базы (не 1С). Com-объект так сделан, что надо сначала получить этот Ид из одного метода и передать в другой. Т.к. возвращаются ИД в виде списка, то я пытаюсь их класть в ТЗ с колонкой неопределенного вида. Однако в момент присваивания (или даже получения) 1С переваривает это значение в Число.

Кто-нибудь может подсказать, как правильно передать такое значение?
1 бомболюк
 
07.04.15
12:22
поиграйся с передачей параметра по значению, может приведет тип как надо.
2 H A D G E H O G s
 
07.04.15
12:26
ComSafeArray с элементом типа uint8

В метод передай одну ячейку этого массива
3 DrShad
 
07.04.15
12:26
Base64Значение
Base64Строка

может оно?
4 H A D G E H O G s
 
07.04.15
12:29
(0) Ваще странная ситуация.
Так как там COM - то входящими параметрами метода могут быть только variant типы, которые легко и непринужденно конвертятся в нужные dll-ке типы (не нарушая сна).
5 DmitrO
 
07.04.15
12:29
Дело в типах передаваемого значения VARIANT (стандартного для COM).

они бывают разных типов
Твой COM объект ожидает либо VT_I8 либо VT_UI8.

1С при взаимодействии с COM принимает любые типы (в том числе и эти) в свой тип Число, однако передает она только так: если число целое передает его как VT_I4, если дробное VT_R8.
Возможно, если целое число будет превышать 4 байта, то она передаст его как VT_I8.

По идее COM объекты поддерживающие automation должны преобразовывать числа на входе если это допустимо, но видимо твой объект об этом не заботится.

т.е. штатных способов не вижу.
6 H A D G E H O G s
 
07.04.15
12:33
то она передаст его как VT_I8.

И какая разница?

Его значение такое же, как и VT_UI8 до переполнения. И так же такое же после 2-х конвертаций

VTUI8->VTI8->VTUI8 при переполнении.
7 DmitrO
 
07.04.15
12:44
(6)вылазь из танка, целые числа она старается передать как VT_I4, но что она будет делать если передаваемое число попросту не войдет в 4 байта, а это любое число больше 2^32, да даже с учетом что она пытается в знаковый тип передать то больше 2^31 - я не знаю, надо проверять.
Но вероятнее всего это не спасет топикстартера, ибо изначально это число он получает от самого COM сервера.

На сколько я понимаю, это сделано специально чтобы было меньше проблем с COM серверами, которые не делают преобразования на входе и ожидают VT_I4, в основном старые, примером одного такого является V77.Application.
8 Serginio1
 
07.04.15
13:00
http://rsdn.ru/?Forum/Default.aspx?ans=1
Первое поле – VARTYPE, которое на самом деле является typedef-ом для unsigned short. Следующие три поля – WORD, еще один typedef для unsigned short. Итак, VARIANT – это 8 байт плюс размер union. Union содержит достаточно места для своего самого большого члена, в данном случае это 8 байт (для double, currency или date). Итак, VARIANT – это 16 байт. Однако есть одно исключение. В Variant поддерживается один забавный тип – DECIMAL. Вот его описание:


struct tagDEC
{
  USHORT wReserved;
9 H A D G E H O G s
 
07.04.15
13:06
(8) Это все знают. Достаточно пошагово отладчиком delphi пройтись при присвоении значения.
10 DmitrO
 
07.04.15
13:06
кстати вот подтверждение из документации:
http://its.1c.ru/db/metod8dev#content:2262:hdoc

Примитивные типы

Значения NULL и Неопределено, а также типы данных Число, Строка, Дата, Булево, определенные в 1С:Предприятии, считаются примитивными. Они представляются аналогичными типами, определенными в VARIANT. Преобразование примитивных типов 1С:Предприятия в VARIANT представлено в таблице:

Тип в 1С:Преприятии    Тип VARIANT
значение NULL    VT_NULL
значение Неопределено    VT_EMPTY
тип Число    Целое в диапазоне от -2147483648 до 2147483647    VT_I4
Другие    VT_R8
тип Строка    VT_BSTR
тип Дата    VT_DATE
тип Булево    VT_BOOL
Примитивные типы и значения, определенные в VARIANT, преобразуются в примитивные типы и значения 1С:Предприятия в соответствии со следующей таблицей.

Тип VARIANT    Тип в 1С:Предприятии
VT_NULL

значение NULL
VT_EMPTY

значение Неопределено
VT_I2, VT_I4, VT_R4, VT_R8, VT_CY, VT_ERROR, VT_DECIMAL, VT_I1, VT_UI1, VT_UI2, VT_UI4, VT_I8, VT_UI8, VT_INT, VT_UINT

тип Число
VT_BSTR    тип Строка
VT_DATE    тип Дата
VT_BOOL    тип Булево
11 DmitrO
 
07.04.15
13:09
(9)а ты в своих COM серверах делаешь преобразование на входе? :)
12 H A D G E H O G s
 
07.04.15
13:10
(11) Конечно

function TBaseVKObject.GetParamAsByte(lIndex: Integer; minValue: byte = 0; maxValue: byte = 255): byte;
var
  varGet: OleVariant;
begin
  SafeArrayGetElement(g_Params, lIndex, varGet);
  try
    Result := varGet;
  except
    ErrorCode := -1 (lIndex + 1);
    ErrorDescription := 'Параметр номер ' + IntToStr(lIndex + 1) + ' не может быть преобразован в целое 1 байтовое баззнаковое.';
    Raise Exception.Create(ErrorDescription);
  end;
  if (Result < minValue) or (Result > maxValue) then
  begin
    ErrorCode := -1
(lIndex + 51);
    Raise Exception.Create('Параметр номер ' + IntToStr(lIndex + 1) + ' преобразован в целое 1 байтовое баззнаковое, но его значение выходит за диапазон: "[' + IntToStr(minValue) + '..' + IntToStr(maxValue) + ']"');
  end;
end;
13 DmitrO
 
07.04.15
13:13
(12)молодец, зачет тебе (!)
что делать топикстартеру с его горем?
14 DmitrO
 
07.04.15
13:14
может через яваскрипт (MSSctriptControl) как нибудь можно извернуться? можно там явно задавать тип варианта?
15 H A D G E H O G s
 
07.04.15
13:14
ErrorCode у меня int64

положительные значения у меня - результаты GetLastError /HResult
отрицательные значения до -50 у меня - ошибки преобразования входящих параметров, от -50 до -100 - выходы за размерности, не тот тип 1С объекта (вместо Массива - ТаблицаЗначений, и.т.д.)
меньше -100 - мои ошибки
16 SpellKeeper
 
07.04.15
13:46
Спасибо за ответы. Даже не ожидал что столько накидаете.

По идее ComSafeArray должен был бы подойти.
Правда, при вызове метода SetValue ругается на неверный тип.
Вот код:
SA = новый ComSafeArray("VT_I8", 1);
SA.SetValue(0,Выборка.IND);
НовСтр.Ид = SA;

Выборка.IND - это то самое значение.
Написал все вроде правильно.

Сейчас пытаюсь выяснить какой же на самом деле тип у этого IND.
17 DmitrO
 
07.04.15
13:56
Да не поможет тебе ComSafeArray никак.
Да, там можно сделать массив нужного типа, но чтобы воспользоваться значением из этого массива, и передать в COM объект, тебе все равно придется его получить от туда.. угу, 1С его получит и преобразует опять в свое Число, ну и передавать будет дальше как обычно.
18 SpellKeeper
 
07.04.15
14:11
Мда. Засада.
Буду знать.

Вообще, я по другом выкрутился. Оказалось, что там то же самое можно получить несколько по-другому.

Спасибо всем.
Программист всегда исправляет последнюю ошибку.