Гость
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид. / 13 сообщений из 13, страница 1 из 1
04.09.2012, 11:06
    #37942468
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
В моем примере из этой темы: 13101649
возвращаются имена аудиоустройств ограниченные MAXPNAMELEN = 32 (31 символ + '\n'):
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
Private Type WAVEOUTCAPS
  wMid As Integer
  wPid As Integer
  vDriverVersion As Long
  szPname As String * MAXPNAMELEN
  dwFormats As Long
  wChannels As Integer
  dwSupport As Long
End Type


========
В моем другом примере: 13109883
возвращаются имена этих же устройств, но не ограниченные 31-им символом.
Но при этом они возвращаются как A pointer to a null-terminated Unicode string in the user default locale :
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
Private Type PROPVARIANT 'http://msdn.microsoft.com/en-us/library/aa380072(v=vs.85).aspx
  vt                                      As Integer 'VT_LPWSTR
  wReserved1                              As Integer
  wReserved2                              As Integer
  wReserved3                              As Integer
  pwszVal                                 As Long   ' union LPWSTR pwszVal;
                                                    'A pointer to a null-terminated Unicode string
                                                    'in the user default locale.
  Padding As Long ' 16 Bytes
...
                Dim varName As PROPVARIANT
                hr = Invoke_(hlPropertyStore, 5, VarPtr(PKEY_Device_FriendlyName), VarPtr(varName))


========
Моя задача:
(1)Сравнить второе с первым (например по первым 31 символам) и если соответствие найдено, то (2)вывести второе на обозрение юзера вместо первого (ибо так юзеру приятнее).
С технической точки зрения (выбор устройства) первого достаточно.

Я столкнулся с Юникодь-проблемой, кот. меня раньше особо не волновали.
То бишь мне надо привести второе к виду первого (надо думать в соответствии c user default locale ).
Сначала я тестировал на Win 7 English, меня это порадовало.
Но потом я рискнул на Vista Russian, и меня знаки вопросиков(только вместо русских букв) огорчили.
Текущий код преобразования Ptr -> ToString такой:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
                Dim varName As PROPVARIANT
                hr = Invoke_(hlPropertyStore, 5, VarPtr(PKEY_Device_FriendlyName), VarPtr(varName))
...
                  the_listbox.AddItem PointerToString(varName.pwszVal)
...
Private Function PointerToString(lngPtr As Long) As String
'NOTE: THE ASSUMPTION IS THAT THE POINTER IS TO A UNICODE STRING
'IF NOT, CHANGE THE FUNCTION AS FOLLOWS (UNTESTED)
'-- Change lstrlenW to lStrLena
'-- Get rid of the * 2
'-- The replace statement should not be necessary, just return strTemp
'----------------------------------------------------------
   
   Dim strTemp As String
   Dim lngLen As Long

   
   If lngPtr Then
      lngLen = lstrlenW(lngPtr) * 2
      If lngLen Then
         strTemp = Space(lngLen)
         CopyMemory ByVal strTemp, ByVal lngPtr, lngLen
         PointerToString = Replace(strTemp, Chr(0), "")
      End If
   End If
End Function



Т.е. чего сделать надо, чтоб допилить?
...
Рейтинг: 0 / 0
04.09.2012, 11:44
    #37942542
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
Советую задавать такие вопросы здесь . Их там любят и быстро отвечают.
...
Рейтинг: 0 / 0
04.09.2012, 11:59
    #37942568
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
Antonariy,
я туда не хожу.
ну а сам ответить не можешь? этот вопрос думаю стандартный, или все-таки сложный?
Просто голова уже не варит после этих ICollections::Inumerators.
...
Рейтинг: 0 / 0
04.09.2012, 12:28
    #37942630
Бенедикт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
Дмитрий77,

по коду PointerToString замечаний, помимо авторских, особо нет. Дело в чём-то другом. Например, в используемой кодировке, OEM-ной (DOS-овской), как вариант; или каким-то боком полученной ANSI-шной строки вместо Unicode-вской. Это надо на коды этих знаков вопроса посмотреть.
По поводу головной боли от ICollections::Enumerators и подобногоИМХО, головной боли будет гораздо меньше, и код будет гораздо более удобоваримым, схожим с сиплюсплюсным или дельфовским (причём где-то более простым), белым и пушистым, если освоить простой, в принципе, язычок ODL, и уметь создавать свои библиотеки типов (если нет готовых, как эта , лучшая в своём роде, но, как не обновляемая автором, уже не поспевающая за современными требованиями) по описаниям интерфейсов в MSDN Library. Та техника, что используется в "французском классе", с ручным созданием таблиц виртуальных методов и вызовами методов по указателю, имеет какой-то смысл в VBA или в случае общей code base для проектов на VB и VBA, и то в основном потому, что для VBA-проектов лишняя ссылка в References - лишняя головная боль при деплое и обновлении.

P. S. Не воспримите за демагогию, проверено на собственной шкуре.
...
Рейтинг: 0 / 0
04.09.2012, 13:16
    #37942764
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
Бенедикт Например, в используемой кодировке, OEM-ной (DOS-овской), как вариант; или каким-то боком полученной ANSI-шной строки вместо Unicode-вской. Это надо на коды этих знаков вопроса посмотреть.
Дык сказано же:
'A pointer to a null-terminated Unicode string in the user default locale .
Собственные инструкции из этого поста 12684884 вроде как выполнены. Просто не умеет видимо VB6 Unicode-строку изображать. И дело ж не только в "отображать", а ее еще надо сравнить с первым вариантом который явно не Юникодовский (там кстати все по русски), т.е. надо преобразовать этот чертов юникод к обычной строке и с ней работать.
Или чего-то не догоняю?

А по поводу "французском класса", я ж его переделал под "немецкий". Думаю такие задачи решать нечасто надо, а опыта как бы прибавилось. Но к слову скажем, на C++ у меня этот код (простой и пушистый) скомпилировать не удалось ну никак. Ломать систему скачивая всякие SDK рука не поднялась, итак эти 2010 экспрессы скрипя понаставил. Компилируешь тот же проект на C++2010 вместо 2005, он не запускается на другом компе, требует каких-то Re-distrabutable. VB.NET с трудом чего-то сделал, лавируя между тем что написал компилятор (а будто мне это надо читать) и выписывая километры всяких System.Marshal, дык он потом .NET 4.X требует. В VB6 как то с этим проще. В Opal из VB6 влез, и мне этого счас с головой хватает.
...
Рейтинг: 0 / 0
04.09.2012, 13:27
    #37942780
Antonariy
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
Дмитрий77Antonariy,
я туда не хожу.Зря. Сэкономил бы кучу времени.
Дмитрий77ну а сам ответить не можешь? Если б знал, ответил бы или ссылку дал.
...
Рейтинг: 0 / 0
04.09.2012, 13:42
    #37942804
Бенедикт
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
Дмитрий77,

Вот это
Код: vbnet
1.
CopyMemory ByVal strTemp

всё-таки не нравится. Попробуйте
Код: vbnet
1.
CopyMemory ByVal StrPtr(strTemp)

"на фсякей".

VB-шные строки в C++ имеют название BSTR, это юникодовские (в понятии MS) строки. А вот с отображением в VB-шных элементах управления могут быть проблемы. Поэтому и говорю - надо бы числовые коды увидеть, они не врут :) .
...
Рейтинг: 0 / 0
04.09.2012, 20:24
    #37943473
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
БенедиктДмитрий77,

Вот это
Код: vbnet
1.
CopyMemory ByVal strTemp

всё-таки не нравится. Попробуйте
Код: vbnet
1.
CopyMemory ByVal StrPtr(strTemp)

"на фсякей".

Если сделать как вы говорите:
Код: vbnet
1.
        CopyMemory ByVal StrPtr(strTemp), ByVal lngPtr, lngLen


то ВЕСЬ текст (включая русский) будет отображаться корректно.

Но: меня смущает то, что если сделать дополнительно так:
Код: vbnet
1.
2.
3.
4.
5.
6.
         'PointerToString = Replace(strTemp, Chr(0), "")
         If InStr(strTemp, Chr(0)) > 0 Then
           strTemp = Left(strTemp, InStr(1, strTemp, Chr(0)) - 1)
         End If
         PointerToString = strTemp
         MsgBox Len(PointerToString)


то
1) не находит Chr(0)
2) при этом показывает в MsgBox длину в 2 раза большую.

Отсюда вывод: тамо в этой PointerToString As String
чуда-юдо мутное сидит .
И непонятно как оно себя будет вести при операциях сравнения букав с другой сторокой (кот. получена первым способом).
Предполагается подбор соответствий по принципу

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
for i=1 to "количество вариантов 2 в списке"
   if left ("вариант2", len ("вариант1")) = "вариант1" then
     отображаем "вариант2" 'вариант 1 сохраняем скажем в tag для реального далнейшего использования
     exit sub
   endif
next i
отображаем "вариант1"

Да и будет ли оно ВСЕГДА корректно отображаться у товарищей на местах (в Китаях, Япониях и Франциях).

Мне то по сути надо получить "обычную" As String в текущей кодировке системы, а у меня там VB-мутант сейчас сидит согласно страшным сказкам с упомянутой VBstreet.
На vbstreet советуется SysAllocString, так понял для конвертации (Unicode)Ptr -> (Обычный)Ptr, но чет у меня пока ничего не выходит. StrConv(str, 128) еще пробовал -творят что хотят.
То русские буквы OK, а EN- знаки вопроса, то строки обрезаются странным образом.
...
Рейтинг: 0 / 0
04.09.2012, 23:59
    #37943646
скукотища
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
Дмитрий77,

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
Private Function PointerToString(lngPtr As Long) As String
' from http://www.freevbcode.com/ShowCode.asp?ID=2643
'--------------------------------------------------------
'RETURNS A STRING FROM IT'S POINTER
'EXAMPLE:
' {skipped}
'----------------------------------------------------------
   
   Dim strTemp As String
   Dim lngLen As Long

   If lngPtr Then
      lngLen = lstrlenW(lngPtr) * 2
      If lngLen Then
         strTemp = Space(lngLen)
         CopyMemory ByVal strTemp, ByVal lngPtr, lngLen
'----------------------------------------------------------
'         PointerToString = Replace(strTemp, Chr(0), "")  ' seat of the trouble
'----------------------------------------------------------
         PointerToString = strTemp
      End If
   End If
End Function


Sub testPointerToString()
  Dim s$, s2$
  Dim l&

  s = "Мастер программист движется от программы к программе без страха." & vbCrLf _
   & "Hикакие изменения в менеджменте не повредят ему." & vbCrLf _
   & "Он не будет уволен даже, если проект будет свернут." & vbCrLf _
   & "Почему так происходит?" & vbCrLf _
   & vbCrLf & "Его наполняет Дао."
 
  l = StrPtr(s)
  s2 = PointerToString(l)

  s2 = StrConv(s2, vbFromUnicode) ' panacea  :)

  MsgBox s2
End Sub

...
Рейтинг: 0 / 0
05.09.2012, 00:39
    #37943669
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
скукотища,

чет мне этот StrConv не нравится совсем.
Я короче сделал так:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
Public Const CP_ACP = 0 'ANSI (default на данной конкретной системе в данный момент)
Public Declare Function WideCharToMultiByte Lib "kernel32" (ByVal CodePage As Long, _
                                                    ByVal dwFlags As Long, _
                                                    ByVal lpWideCharStr As Long, _
                                                    ByVal cchWideChar As Long, _
                                                    ByVal lpMultiByteStr As Long, _
                                                    ByVal cbMultiByte As Long, _
                                                    ByVal lpDefaultChar As Long, _
                                                    ByVal lpUsedDefaultChar As Long) As Long

Private Function PointerToString(lngPtr As Long) As String
  Dim lLenB As Long
  Dim bytBuffer() As Byte
  Dim lRet As Long
  Dim i As Long
  Dim str As String
  str = ""
  If lngPtr <> 0 Then
    lLenB = lstrlenW(lngPtr)
    If lLenB <> 0 Then
      ReDim bytBuffer(lLenB - 1) 'нулевой байт добавлять нет смысла
      lRet = WideCharToMultiByte(CP_ACP, 0&, ByVal lngPtr, -1, ByVal VarPtr(bytBuffer(0)), lLenB, 0&, 0&)
      For i = 0 To lLenB - 1
        If bytBuffer(i) = 0 Then Exit For 'страховка
        str = str & Chr(bytBuffer(i))
      Next i
    End If
  End If
  PointerToString = str
End Function


И вот теперь я уверен что всегда найду соответствия между Вариант1 и Вариант2.
Wave функции отдают ANSI, а никак не юникод.
...
Рейтинг: 0 / 0
05.09.2012, 01:11
    #37943682
скукотища
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
> Дмитрий77,
> чет мне этот StrConv не нравится совсем.
> Я короче сделал так:

Не нравится, так не нравится, - насильно мил не будешь.
Работает, - ну и ладно.

> Wave функции отдают ANSI, а никак не юникод.
Честно говоря, не понял, к чему Вы это.. Ведь проблема, насколько понял, была именно в получении ANSI-string изA pointer to a null-terminated Unicode string in the user default locale.при наличии в возвращаемой строке национальных символов.
...
Рейтинг: 0 / 0
05.09.2012, 01:41
    #37943685
Дмитрий77
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
скукотища,

Replace(strTemp, Chr(0), "") -это конечно чушь полная.
Но дело в том, что если оставить как вы написали, то строки которые as String будут удвоенной длины len(str).
Т.е. не уверен что с ними можно нормально работать, а если сделать:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
Private Function PointerToStringUnicode(lngPtr As Long) As String
   Dim strTemp As String
   Dim lngLen As Long


   If lngPtr Then
      lngLen = lstrlenW(lngPtr) * 2
      If lngLen Then
         strTemp = Space(lngLen)
         CopyMemory ByVal StrPtr(strTemp), ByVal lngPtr, lngLen
         PointerToStringUnicode = StrConv(strTemp, vbFromUnicode)
         MsgBox Len(PointerToStringUnicode)
      End If
   End If
End Function


то будет выдавать полную чушь.
Причем 3-й параметр -LocaleID согласно документации =default, он не срабатывает что-ли,
даже если написать 1049 для проверки, то ничего не меняется.

В моем примере с API по крайней мере ясно что
1) есть указатель lngPtr на LPWSTR
2) есть дефолная кодовая таблица CP_ACP по которой переводим в ANSI
3) есть длина строки lstrlenW в буквах
4) на выходе имеем НЕ-юникод массив нормальных байтов bytBuffer()
5) с этими байтами тупо и по одному разбираемся понятным способом

И самое главное результат соответствует обоснованным ожиданиям и полученный объект обладает привычными для таковых свойствами (например len() соответствует к-ву буков). А чего там StrConv делает и че VB понимает под As string в первом варианте и можно ли на это полагаться это сам черт не разберет.
...
Рейтинг: 0 / 0
05.09.2012, 03:04
    #37943698
скукотища
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид.
Дмитрий77,
не готов сейчас дискутировать "по-полной".
Есть замечание: LCID из StrConv это далеко не то же самое, что CodePage из WideCharToMultiByte.

ЗЫ:
... действительно, если StrConv вызывать внутри PointerToString то чушь получается полная. *недоумение
Если скармливать ей результат PointerToString - то результат приемлимый, как по длине строки, так и по содержанию.
...
Рейтинг: 0 / 0
Форумы / Visual Basic [игнор отключен] [закрыт для гостей] / API -ф-ция возвращает указатель на LPWSTR, как переварить в нормальный вид. / 13 сообщений из 13, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]