Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
 А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4407
FaxDocument.ConnectedSubmit method (аналогично .ConnectedSubmit2 )
В VB.Net это будет

Function ConnectedSubmit(pFaxServer As FAXCOMEXLib.IFaxServer) As Object


Return value
Type: Variant*
Variant that holds an array of outbound job ID strings, one for each recipient of the fax.

Тип там VARIANT VT_ARRAY|VT_BSTR (8192|8 ==8200)

Начало кода я легко накатал, т.к. недавно успешно повоевал с VT_ARRAY|VT_UI1

  <StructLayout(LayoutKind.Sequential)>
  Public Structure tagVARIANTparray
    Dim vt As Short ' VT_ARRAY|VT_UI1 для SECURITY_DESCRIPTOR
    Dim wReserved1 As Short
    Dim wReserved2 As Short
    Dim wReserved3 As Short
    Dim parray As IntPtr
  End StructureDim vJobID As IntPtr
    Dim tV As tagVARIANTparray
    Try
      vJobID = Marshal.AllocCoTaskMem(16) 'VARIANT – это 16 байт
      Marshal.GetNativeVariantForObject(JobID, vJobID)
      tV = CType(Marshal.PtrToStructure(vJobID, GetType(tagVARIANTparray)), tagVARIANTparray)
      Debug.Print("      Obtaining JobID (VARIANT VT_ARRAY|VT_BSTR)... OK.")
    Catch
      Debug.Print("      Obtaining JobID (VARIANT VT_ARRAY|VT_BSTR)... Failed. Error=" & Err.Number.ToString & " (" & Err.Description & ")")
      GoTo ToExit
    End Try
    'Dim strJobID As String = Marshal.PtrToStringBSTR(tV.parray)
    'MsgBox(tV.parray)

ToExit:
    'VariantClear(tV) '!!! ??? не стоит этого здесь делать, рискуем потерять ???
    If vJobID <> IntPtr.Zero Then Marshal.FreeCoTaskMem(vJobID)

...


Т.е. имеем vJobID.vt = VARIANT VT_ARRAY|VT_BSTR (8192|8 ==8200) -проверил, все ОК

vJobID.parray As IntPtr -получил,
это указатель на искомый VT_ARRAY, состоящий из VT_BSTR
Как из него массив String() выковырять?
(Marshal.PtrToStringBSTR видимо при делах, но ясно что не так как я на дурака попытался)
7 май 19, 17:19    [21880187]     Ответить | Цитировать Сообщить модератору
 Re: А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
ЕвгенийВ
Member

Откуда: Москва
Сообщений: 4817
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1358&mode=print
7 май 19, 17:53    [21880227]     Ответить | Цитировать Сообщить модератору
 Re: А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4407
Вроде расковырял методом научного тыка, все работает.
Сделал ф-цию Object -> String().
Мучают смутные сомнения насчет того надо или не надо делать
VariantClear(tV)
Marshal.FreeBSTR(pArray(i))
??? Интуиция почему-то подсказывает что таки в данном конкретном случае не надо (лучшее враг хорошего)
Хотя черт его знает.
SafeArrayAccessData/SafeArrayUnaccessData я делаю
Marshal.FreeCoTaskMem(vArray) тоже делаю,
есть соображения что все остальные проблемы, это проблемы oArray As Object (который отдает мне COM)
Не пложу ли я новой неочищенной памяти через Marshal.GetNativeVariantForObject,Marshal.Copy, Marshal.PtrToStringBSTR…?
Если какая-то "утечка" явно бросается в глаза, просьба указать.


    Dim strJobID() As String = GetStringArrayFromObject(JobID)

    If Not strJobID Is Nothing Then
      For i As Integer = 0 To UBound(strJobID)
        Debug.Print("Job #" & i.ToString & ":" & strJobID(i))
      Next
    End IfPublic Const VT_BSTR = 8
  Public Const VT_ARRAY = 8192

  <StructLayout(LayoutKind.Sequential)>
  Public Structure tagVARIANTparray
    Dim vt As Short ' VT_ARRAY|VT_UI1 для SECURITY_DESCRIPTOR
    Dim wReserved1 As Short
    Dim wReserved2 As Short
    Dim wReserved3 As Short
    Dim parray As IntPtr
  End Structure

  Public Declare Function SafeArrayGetUBound Lib "OleAut32.dll" _
   (ByVal psa As IntPtr, ByVal nDim As Integer, ByRef plUbound As Integer) As Integer
  Public Declare Function SafeArrayAccessData Lib "OleAut32.dll" _
   (ByVal psa As IntPtr, ByRef ppvData As IntPtr) As Integer
  Public Declare Function SafeArrayUnaccessData Lib "OleAut32.dll" (ByVal psa As IntPtr) As Integer


  Public Function GetStringArrayFromObject(ByRef oArray As Object) As String()
    Dim strArray() As String = Nothing

    Dim vArray As IntPtr
    Dim tV As tagVARIANTparray
    Dim hr As Integer
    Try
      vArray = Marshal.AllocCoTaskMem(16) 'VARIANT – это 16 байт
      Marshal.GetNativeVariantForObject(oArray, vArray)
      tV = CType(Marshal.PtrToStructure(vArray, GetType(tagVARIANTparray)), tagVARIANTparray)
      Debug.Print("Marshal.GetNativeVariantForObject... OK.")
    Catch
      Debug.Print("Marshal.GetNativeVariantForObject... Failed. Error=" & Err.Number.ToString & " (" & Err.Description & ")")
      GoTo ToExit
    End Try

    If tV.vt = (VT_ARRAY Or VT_BSTR) Then
      Debug.Print("Variant type is VARIANT VT_ARRAY|VT_BSTR... OK.")
    Else
      Debug.Print("Variant type is not VARIANT VT_ARRAY|VT_BSTR... Failed.")
      GoTo ToExit
    End If

    Dim UB As Integer
    hr = SafeArrayGetUBound(tV.parray, 1, UB)
    If hr < 0 Then
      Debug.Print("Calling SafeArrayGetUBound... Failed. Error code: " & RaiseAPIErrorByNumber(hr))
      GoTo ToExit
    End If
    Debug.Print("Calling SafeArrayGetUBound... OK. UBound = " & UB.ToString)
    If UB < 0 Then GoTo ToExit

    Dim ppArray As IntPtr 'указатель на массив указателей
    hr = SafeArrayAccessData(tV.parray, ppArray)
    If hr < 0 Then
      Debug.Print("Calling SafeArrayAccessData... Failed. Error code: " & RaiseAPIErrorByNumber(hr))
      GoTo ToExit
    End If
    Debug.Print("Calling SafeArrayAccessData... OK.")

    Dim pArray(0 To UB) As IntPtr 'массив указателей на bstr (размерность уже известна)
    Marshal.Copy(ppArray, pArray, 0, UB + 1)
    For i As Integer = 0 To UB
      ReDim Preserve strArray(0 To i)
      strArray(i) = Marshal.PtrToStringBSTR(pArray(i))
    Next

    hr = SafeArrayUnaccessData(tV.parray)
    If hr < 0 Then
      'Failed to unaccess safearray
      Debug.Print("Calling SafeArrayUnaccessData... Failed. Error code: " & RaiseAPIErrorByNumber(hr))
    End If
    Debug.Print("Calling SafeArrayUnaccessData... OK.")

ToExit:
    If vArray <> IntPtr.Zero Then Marshal.FreeCoTaskMem(vArray)
    Return strArray
  End Function
8 май 19, 05:34    [21880555]     Ответить | Цитировать Сообщить модератору
 Re: А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
Изопропил
Member

Откуда:
Сообщений: 31209
Дмитрий77,

Нижняя граница safearray может быть не ноль
Размер варианта в x64 не 16, а 24
8 май 19, 08:23    [21880610]     Ответить | Цитировать Сообщить модератору
 Re: А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4407
Изопропил
Нижняя граница safearray может быть не ноль

Я обратил внимание на SafeArrayGetLBound, там еще SafeArrayGetDim в общем случае по хорошему.
Но в маразм наверно не стоит входить до такой степени.
100% уверен, что в интересуемых меня ConnectedSubmit2/ConnectedSubmit всегда
LBound==0 GetDim==0 (ну либо метод вернул False, тогда там понятно ничего нет, хотя на всяк. случай проверяю что LBound>=0)
Оставлю как есть, не вижу смысла умничать.
Изопропил
Размер варианта в x64 не 16, а 24

Сначала было кинулся исправлять, но почитал еще раз: VARIANT и SafeArray, посмотрел на этот UNION и на свою Structure tagVARIANTparray.
У меня по-любому частный случай: 8 байт + указатель на SafeArray.
Т.е. на x64 ==16, а на x86 -вообще ==12 (т.е. перебор, но больше не меньше).
(опять же, я же знаю какой именно Variant VT_ARRAY|VT_BSTR там сидит).
Поэтому опять же, не вижу смысла чего-то менять.

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

Вообще конечно интересные хрени получаются. FaxComEx (как и любой COM) ориентирован типа на школьника, чтоб ему легко все написать без танцев с "API" (изначально ясен пень ориентировано на VB6, хотя в VB.Net суть та же), но когда какой нибудь Security Descriptor или все-го то набор JobID возвращается как "As Object", такие пляски недетские нужны с теми же самыми C-API.

Мне б конечно ближе сразу делать через классические C-API, они как бы это выразиться "четче работают и обработка ошибок яснее" но те которые "для Win 2000" (соответствуют FaxCom без Ex)… То что там MS рекомендует и пишет Depricated, это по… (они уже сами запутались со своим "Modern GUI") НО к сожалению эти "C-API для Win 2000" тупо не покрывают тот часто нужный функционал, кот. появился в XP/2003, а некоторый только в Висте. (как пример в C-структуре для Cover Page тупо отсутствует поле для Sender Email - видимо email в середине-конце 90-х был чем-то неактуальным и бесполезным)
8 май 19, 17:56    [21881376]     Ответить | Цитировать Сообщить модератору
 Re: А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4407
Дмитрий77
GetDim==0

GetDim==1 одномерный массив имелось ввиду
8 май 19, 18:01    [21881380]     Ответить | Цитировать Сообщить модератору
 Re: А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4407
Код, что я привел двумя постами выше
+
    Dim strJobID() As String = GetStringArrayFromObject(JobID)

    If Not strJobID Is Nothing Then
      For i As Integer = 0 To UBound(strJobID)
        Debug.Print("Job #" & i.ToString & ":" & strJobID(i))
      Next
    End IfPublic Const VT_BSTR = 8
  Public Const VT_ARRAY = 8192

  <StructLayout(LayoutKind.Sequential)>
  Public Structure tagVARIANTparray
    Dim vt As Short ' VT_ARRAY|VT_UI1 для SECURITY_DESCRIPTOR
    Dim wReserved1 As Short
    Dim wReserved2 As Short
    Dim wReserved3 As Short
    Dim parray As IntPtr
  End Structure

  Public Declare Function SafeArrayGetUBound Lib "OleAut32.dll" _
   (ByVal psa As IntPtr, ByVal nDim As Integer, ByRef plUbound As Integer) As Integer
  Public Declare Function SafeArrayAccessData Lib "OleAut32.dll" _
   (ByVal psa As IntPtr, ByRef ppvData As IntPtr) As Integer
  Public Declare Function SafeArrayUnaccessData Lib "OleAut32.dll" (ByVal psa As IntPtr) As Integer


  Public Function GetStringArrayFromObject(ByRef oArray As Object) As String()
    Dim strArray() As String = Nothing

    Dim vArray As IntPtr
    Dim tV As tagVARIANTparray
    Dim hr As Integer
    Try
      vArray = Marshal.AllocCoTaskMem(16) 'VARIANT – это 16 байт
      Marshal.GetNativeVariantForObject(oArray, vArray)
      tV = CType(Marshal.PtrToStructure(vArray, GetType(tagVARIANTparray)), tagVARIANTparray)
      Debug.Print("Marshal.GetNativeVariantForObject... OK.")
    Catch
      Debug.Print("Marshal.GetNativeVariantForObject... Failed. Error=" & Err.Number.ToString & " (" & Err.Description & ")")
      GoTo ToExit
    End Try

    If tV.vt = (VT_ARRAY Or VT_BSTR) Then
      Debug.Print("Variant type is VARIANT VT_ARRAY|VT_BSTR... OK.")
    Else
      Debug.Print("Variant type is not VARIANT VT_ARRAY|VT_BSTR... Failed.")
      GoTo ToExit
    End If

    Dim UB As Integer
    hr = SafeArrayGetUBound(tV.parray, 1, UB)
    If hr < 0 Then
      Debug.Print("Calling SafeArrayGetUBound... Failed. Error code: " & RaiseAPIErrorByNumber(hr))
      GoTo ToExit
    End If
    Debug.Print("Calling SafeArrayGetUBound... OK. UBound = " & UB.ToString)
    If UB < 0 Then GoTo ToExit

    Dim ppArray As IntPtr 'указатель на массив указателей
    hr = SafeArrayAccessData(tV.parray, ppArray)
    If hr < 0 Then
      Debug.Print("Calling SafeArrayAccessData... Failed. Error code: " & RaiseAPIErrorByNumber(hr))
      GoTo ToExit
    End If
    Debug.Print("Calling SafeArrayAccessData... OK.")

    Dim pArray(0 To UB) As IntPtr 'массив указателей на bstr (размерность уже известна)
    Marshal.Copy(ppArray, pArray, 0, UB + 1)
    For i As Integer = 0 To UB
      ReDim Preserve strArray(0 To i)
      strArray(i) = Marshal.PtrToStringBSTR(pArray(i))
    Next

    hr = SafeArrayUnaccessData(tV.parray)
    If hr < 0 Then
      'Failed to unaccess safearray
      Debug.Print("Calling SafeArrayUnaccessData... Failed. Error code: " & RaiseAPIErrorByNumber(hr))
    End If
    Debug.Print("Calling SafeArrayUnaccessData... OK.")

ToExit:
    If vArray <> IntPtr.Zero Then Marshal.FreeCoTaskMem(vArray)
    Return strArray
  End Function

Проверил, уже наваявши много, не работает зараза на XP (32 бит), т.е. работает но выдает не то.
На Win2003 (32 бит), и на Win10 x64 все OK.

Взял один и тот же Exe-шник, Net 2.0+Release+x86.
Вот что имеем:
=====Win10======
05.23.2019@03:29:27.233:   Operation System: Windows 10 10.0 build 17134
05.23.2019@03:29:27.233:   Environment: x64
...
05.23.2019@03:29:29.561:   Submitting fax job(s)... OK.
05.23.2019@03:29:29.577:       JobID(s): 201d510fe95a454
05.23.2019@03:29:29.577:   Starting tracking fax status (JobID=201d510fe95a454)
05.23.2019@03:29:29.780:   EVENT: OnOutgoingJobAdded (JobId=201d510fe95a454)

=====Win2003======
05.23.2019@04:08:58.388:   Operation System: Windows Server 2003 R2 5.2 build 3790 (Service Pack 2)
05.23.2019@04:08:58.388:   Environment: Win32
...
05.23.2019@04:08:58.826:   Submitting fax job(s)... OK.
05.23.2019@04:08:58.826:       JobID(s): 201d510fbb80ea1
05.23.2019@04:08:58.826:   Starting tracking fax status (JobID=201d510fbb80ea1)
05.23.2019@04:08:58.935:   EVENT: OnOutgoingJobAdded (JobId=201d510fbb80ea1)

=====WinXP======
05.22.2019@16:45:53.187:   Operation System: Windows XP 5.1 build 2600 (Service Pack 3)
05.22.2019@16:45:53.187:   Environment: Win32
…
05.22.2019@16:45:53.718:   Submitting fax job(s)... OK.
05.22.2019@16:45:53.718:   Marshal.GetNativeVariantForObject... OK.
05.22.2019@16:45:53.718:   Variant type is VARIANT VT_ARRAY|VT_BSTR... OK.
05.22.2019@16:45:53.718:   Calling SafeArrayGetUBound... OK. UBound = 0
05.22.2019@16:45:53.718:   Calling SafeArrayAccessData... OK.
05.22.2019@16:45:53.718:   Calling SafeArrayUnaccessData... OK.
05.22.2019@16:45:53.718:       JobID(s): 144630930370922981
05.22.2019@16:45:53.718:   Starting tracking fax status (JobID=144630930370922981) //выдает явно не hex-образную строку
05.22.2019@16:45:53.828:   EVENT: OnOutgoingJobAdded (JobId=201d5109c4b09e5) //а это то что должно быть
-----кусок другого лога, чтоб попытаться понять закономерность
05.22.2019@17:14:26.859:       JobID(s): 144630930437842551
05.22.2019@17:14:26.859:   Starting tracking fax status (JobID=144630930437842551) //выдает явно не hex-образную строку
05.22.2019@17:14:26.953:   EVENT: OnOutgoingJobAdded (JobId=201d510a0482677) //а это то что должно быть


Т.е. проблема в том что моя GetStringArrayFromObject должна мне вернуть набор строк вида "201d5109c4b09e5", а она мне выдает вида "144630930370922981"(только на XP!!!) , и я вот думаю, это я вообще "не то прочитал", или почему-то оно прочиталось "не в том формате".
То что с комментом EVENT, это то что возвращается из события как "bstrJobId As String" (согласно COM) и оно должно совпадать с тем что я выкопал из Object (первый элемент массива VARIANT VT_ARRAY|VT_BSTR).

То что ошибка в COM /Interop, я сомневаюсь (Interop этот когда-то делался специально под .Net 2.0 и чуть ли не на XP под старой студией, специально чтоб обладать нужной универсальностью).
Либо я в коде ковыряния Object-а ляп сделал, либо Marshall на XP глючит.

На XP свет клином не сошелся, но неприятно и пока не понимаю почему такой "эффект".
23 май 19, 04:12    [21891403]     Ответить | Цитировать Сообщить модератору
 Re: А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4407
А самое интересное, что моя GetStringArrayFromObject (),
таки эквивалентна одной строчке кода.

Как читать тип варианта в Visual С# 2010 из объекта COM (VB)

    'Dim strJobID() As String = GetStringArrayFromObject(JobID)
    Dim strJobID() As String = CType(JobID, String())

Печально, ступил.

Проблема в том, что и с этой "одной строчкой кода" в XP получаем
"144630930370922981" вместо "201d5109c4b09e5"
"144630930437842551" вместо "201d510a0482677"
Мож "конвертануть" как-то?
Понять не могу, почему так (ошибки в моей API-ф-ции стало быть нет).
23 май 19, 04:59    [21891405]     Ответить | Цитировать Сообщить модератору
 Re: А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4407
в XP получаем
"144630930370922981" вместо "201d5109c4b09e5"
"144630930437842551" вместо "201d510a0482677"
Мож "конвертануть" как-то?

Получилось
Decimal to Hexadecimal Converter
Бред какой-то. А че он на XP в Decimal то отдает...?

1) Как проверить что в моей строке сидит Decimal а не Hex? (программно)
2) Как конвертануть Decimal в Hex? (программно)
(у меня по любому As String на входе и выходе)
23 май 19, 05:27    [21891406]     Ответить | Цитировать Сообщить модератору
 Re: А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4407
Дмитрий77
2) Как конвертануть Decimal в Hex? (программно)

TextBoxHex.Text = LCase(Hex(TextBoxDecimal.Text))


Обратно вроде так работает, но мне не надо
TextBoxDecimal.Text = Convert.ToInt64(TextBoxHex.Text, 16).ToString

Дмитрий77
1) Как проверить что в моей строке сидит Decimal а не Hex? (программно)

???
Т.е. я де-факто не знаю, вернули ли мне строку как Decimal или как Hex,
но она по-любому мне нужна в Hex.
Я не уверен, что на XP точно Decimal, а на >=win2003 точно Hex.
Я не нашел такой документации, м.б. от чего друго-го зависит.
Но странно то что одно и то же так по разному себя ведет.
23 май 19, 07:10    [21891422]     Ответить | Цитировать Сообщить модератору
 Re: А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4407
Все, разобрался.
Почитал вот рассуждения людей
JobID, a pointer or just worthless?

XP -это fsAPI_VERSION_1
Win2003 -это fsAPI_VERSION_2 (и сюда же кстати XP x64)
все что выше Висты - это fsAPI_VERSION_3
fsAPI_VERSION_1 возвращает строку аля-Int64
все что выше возвращает строку в Hex (в нижнем регистре)
Все события (включая проблемную fsAPI_VERSION_1) возвращают ID в формате Hex (в нижнем регистре),
т.е. отслеживать сравнивать всегда надо в Hex.
Плясать правильно от FAX_SERVER_APIVERSION, а не от OS, и для fsAPI_VERSION_1 конвертировать в Hex.

Проблема еще в том, что оф. доки путанные, и про Int64/Hex информации нет.

    strJobID = CType(JobID, String())

    'Converting JobID(s) from Int64 string to Hex string
    'https://docs.microsoft.com/en-us/windows/desktop/api/faxcomex/ne-faxcomex-fax_server_apiversion_enum
    ' fsAPI_VERSION_0 -Win2000(Not Supported); fsAPI_VERSION_1 - Windows XP !!!32бит (Int64 string)
    ' fsAPI_VERSION_2 -Windows Server 2003 (+ Windows XP !!!64бит==Win2003); fsAPI_VERSION_3 - Windows Vista+ (Hex string)
    If FaxServerApiVersion = FAXCOMEXLib.FAX_SERVER_APIVERSION_ENUM.fsAPI_VERSION_1 _
     Or FAXCOMEXLib.FAX_SERVER_APIVERSION_ENUM.fsAPI_VERSION_0 Then
      If IsNothing(strJobID) = False Then
        For i = 0 To UBound(strJobID)
          'на всякий случай проверяем, что это число
          If IsNumeric(strJobID(i)) Then strJobID(i) = LCase(Hex(CType(strJobID(i), Int64)))
        Next
      End If
    End If
23 май 19, 18:56    [21892409]     Ответить | Цитировать Сообщить модератору
 Re: А как ковырять VARIANT VT_ARRAY|VT_BSTR сидящий в As Object?  [new]
Дмитрий77
Member

Откуда:
Сообщений: 4407
Неаккуратно записал условие, хотя за счет fsAPI_VERSION_0==0 сработает правильно, но тем не менее это ляпс.

FaxServerApiVersion = g_objFaxServer.APIVersion
…
    strJobID = CType(JobID, String())
...
    'Converting JobID(s) from Int64 string to Hex string
    'https://docs.microsoft.com/en-us/windows/desktop/api/faxcomex/ne-faxcomex-fax_server_apiversion_enum
    ' fsAPI_VERSION_0 -Win2000(Not Supported); fsAPI_VERSION_1 - Windows XP !!!32бит (Int64 string)
    ' fsAPI_VERSION_2 -Windows Server 2003 (+ Windows XP !!!64бит==Win2003); fsAPI_VERSION_3 - Windows Vista+ (Hex string)
    If (FaxServerApiVersion = FAXCOMEXLib.FAX_SERVER_APIVERSION_ENUM.fsAPI_VERSION_1) _
     Or (FaxServerApiVersion = FAXCOMEXLib.FAX_SERVER_APIVERSION_ENUM.fsAPI_VERSION_0) Then
      If IsNothing(strJobID) = False Then
        For i = 0 To UBound(strJobID)
          'на всякий случай проверяем, что это число
          If IsNumeric(strJobID(i)) Then strJobID(i) = LCase(Hex(CType(strJobID(i), Int64)))
        Next
      End If
    End If
23 май 19, 19:43    [21892455]     Ответить | Цитировать Сообщить модератору
Все форумы / WinForms, .Net Framework Ответить