Адаптация VB к Сишной библе. Не получается создать структуру

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение ALX_2002 » 03.03.2009 (Вт) 11:35

Доброго времени суток господа. В прошлом году заходил сюда с подобными вопросами. Сейчас снова столкнулся с той же проблемой. Старую тему к сожалению обнаружить не смог. :|. Хотел в ней продолжить. Наверное плохо искал. Ну начну заного - Есть сишная библиотека комплекса шифрования Verba. Пытаюсь сгородить на неё оболочку в виде COM компонента для удобства автоматизации.

Столкнулся с проблемой адаптации функции

Для проверки подписи под файлом служит функция check_file_sign(wbotho, wsigno), которая имеет следующий прототип:
T16bit WINAPI check_file_sign (char *file_name,
P8bit count,
Check_Status_Ptr *stat_array);
Функция имеет следующие параметры:
(i) file_name — указатель на строку полного пути к файлу;
(o) count — указатель на переменную, в которую записывается количество обнаруженных подписей;
(o) stat_array — массив результатов проверки каждой подписи, элементами которого являются структуры (структура описана в файле verba.h):
#define NAME_LEN 12
#define NAME_LEN 120
typedef struct tagCheck_Status {
char Name[NAME_LEN+1];
char Alias[ALIAS_LEN+1];
T8bit Position;
T8bit Status;
T32bit Date;
} Check_Status;
typedef Check_Status *Check_Status_Ptr;
#define CHECK_STATUS_LEN sizeof(Check_Status)
• Каждая структура содержит:
• идентификатор ключа;
• описание (текстовые атрибуты);
• порядковый номер подписи;
• гринвическое время (UTC) формирования подписи (time_t);
Внимание. Данный формат для времени формирования подписи используется начиная с версии библиотек СКЗИ 5.0 .
• результат проверки:
0 = CORRECT — подпись верна;
1 = NOT_CORRECT — подпись не верна;
2 = OKEY_NOT_FOUND — открытый ключ для проверки подписи не найден.
Внимание. Память под этот массив отводится внутри функции check_file_sign и должна быть освобождена функцией FreeMemory (см. п. 8.12), как только stat_array будет обработан.
Пример использования функции check_file_sign:
unsigned char count;
Check_Status_Ptr status_array;
...
error_code = check_file_sign("C:\\TEST.TST", &count, &status_array);
if(error_code) return(error_code);
for(i = 0; i < count; i++)
printf("%u-%u\n", status_array[i].Position, status_array[i].Status);
FreeMemory(status_array);


Попытался сделать аналог на основании старых исходников.

Код: Выделить всё
Private Type tagCheck_Status
    Name As String
    Alias As String
    Position As Byte
    Status As Byte
    Date As Long
End Type

Private Declare Function check_file_sign Lib "wbotho.dll" (file_name As String, Count As Byte, Check_Status_Ptr As tagCheck_Status)
Private Sub Form_Load()
    Dim Count As Byte
    Dim Check_Status_Ptr(5) As tagCheck_Status
    check_file_sign App.Path & "\1.txt", Count, Check_Status_Ptr(0)
End Sub


Явно понимаю, кто криво подсовываю, но не хватает знаний для того чтоб правильно собрать. :?

Очень надеюсь на вашу помощь.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение Хакер » 03.03.2009 (Вт) 12:23

Эээ. Не переведёшь ты её просто так.

И дело тут не столько в структуре.
В частности, третий параметр функции не указатель на первый элемент массива, а указатель на указатель на первый элемент массива.

Т.е. ты в VB-коде должен объявить указатель (но в VB нет возможности объявить его, но есть мой трюк) на первый элемент массива, но сам ты этот указатель (назовём его альфа-указателем, чтобы не путать с другими) трогать не должен. В функцию ты должен передать указатель на альфа-указатель, т.е. адрес альфа-указателя, или в рамках VB этому будет эквивалентна передача альфа-указателя ByRef.

Функция сама выделит память (а ты в своём VB-варианте выделяешь сам) под массив, что логично, потому что только она знает, сколько элементов в нём будет, и запишет (сама!) в твой альфа-указатель адрес первого элемента этого массива.

Так что у тебя есть три варианта:
1) Перейти полностью на лонги, отказавшись от языковых средств, и потом расковыривать структуры в памяти самому.
2) Перейти на мой трюк, получив возможность в VB объявлять указатели. Тогда всё существенно проще.
3) А ещё можно объявить VB-дин-массив, получить его SA-дескриптор, и в функцию передать в качестве второго параметра: адрес SA.cbElements, а в качестве третьего: адрес SA.pvData.

Тогда с массивом структур можно будет работать прозрачно, как с обычным массивом.

Кроме всего этого есть ещё одна грубая ошибка: у тебя фукция имеет тип возврата Variant. Одного этого достаточно, чтобы всё падало.

Ну и в объявлении самой структуры строки сделать ни в коем случае ни как String, а как фикс. байтовые массивы. И то, не ясно, совпадает ли у C++-компилятора и VB мнение насчёт выравнивания полей.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение ALX_2002 » 03.03.2009 (Вт) 12:44

2 Хакер:
:shock: Дочитал до конца....
1) Глаз дёргается
2) Нервно хихикаю
3) Бьюсь головой о стену
:shock: Бедный мой моск...

Кхм... Собрались...

1) А что проще всего реализовать ? Минимумом затрат и простотой кода и без дополнительных библиотек, если это возможно ?
2) А где можно этот трюк посмотреть ? :shock:
3) Пока что посидел - не совсем въехал с объявлением Char-овых параметров как Byte массив. Обратил внимание на

Код: Выделить всё
#define NAME_LEN   12
#define NAME_LEN   120


Тогда NameParam(13) As Byte и Alias(121) As Byte ? Или в 2 раза увеличить надо ? :oops: Позорно туплю.

Объявление функции as long поставил. Но вот указатель на указатель.... это за гранью моего понимания :drunken:
Код: Выделить всё
Private Type tagCheck_Status
    NameParam(13) As Byte
    Alias(121) As Byte
    Position As Byte
    Status As Byte
    Date As Long
End Type

Private Declare Function check_file_sign Lib "wbotho.dll" (ByVal file_name As String, ByRef Count As Byte, ByRef Check_Status_Ptr As tagCheck_Status) As Long
Private Sub Form_Load()
    Dim Count As Byte
    Dim Check_Status_Ptr() As tagCheck_Status
    ReDim Check_Status_Ptr(0)
    check_file_sign App.Path & "\1.txt", Count, Check_Status_Ptr(0)
End Sub


* Добавлено позже

Потестил код. Заметил - новую особенность. Перестала появляться ошибка Bad DLL Conversion. В переменную Count вернулось - 1. По идее одну подпись я всё таки нашёл. В массив Check_Status_Ptr не вернулось ничего. Ну эт логично - указатель на указатель я не подсунул ещё. :D Ну хоть ошибки нет. Уже радует. А то замучался этом МЫСЫГЫБОКС закрывать каждый раз.

* Добавлено ещё позже

Хм... Получил в NameParam крякозяблу типа ?Ы. Мысль - либо как то криво сработало и я структурой попал на левые данные, либо это Unicode. Комент с получением размера массива тож озадачил. Привык, что массив я либо создаю заранее, либо делаю незаданным и редимлю. а тут - эшельбе мешельбе нащальника. :shock: Шайтана.

Код: Выделить всё
Private Type tagCheck_Status
    NameParam(12) As Byte
    Alias(120) As Byte
    Position As Byte
    Status As Byte
    Date As Long
End Type

Private Declare Function check_file_sign Lib "wbotho.dll" (ByVal file_name As String, ByRef Count As Byte, ByRef Check_Status_Ptr As tagCheck_Status) As Long
Private Sub Form_Load()
    Dim Count As Byte
    Dim Check_Status_Ptr(10) As tagCheck_Status
'    ReDim Check_Status_Ptr(2)
    error_code = check_file_sign(App.Path & "\27911469.KVT", Count, Check_Status_Ptr(0))

    MsgBox Check_Status_Ptr(0).NameParam
End Sub

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение jangle » 03.03.2009 (Вт) 13:30

Выложил бы wbotho.dll в аттач, другие бы тоже потестили

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение Хакер » 03.03.2009 (Вт) 13:33

1) А что проще всего реализовать ? Минимумом затрат и простотой кода и без дополнительных библиотек, если это возможно ?

Ну, мне все они кажутся простыми, но быстрее и проще (даже понимаемость кода выше) должны быть второй и третий вариант. Доп. библиотек не исопльзуется ни в одном из вариантов.

2) А где можно этот трюк посмотреть ? :shock:

Э... МануAll / Об указательях в VB6

3) Пока что посидел - не совсем въехал с объявлением Char-овых параметров как Byte массив. Обратил внимание на


Код: Выделить всё
#define NAME_LEN   12
#define NAME_LEN   120


Тогда NameParam(13) As Byte и Alias(121) As Byte ? Или в 2 раза увеличить надо ? :oops: Позорно туплю.

В два раза увеличивать не надо, потому что ANSI. Но ступил ты вот в чём: в сишных массивах число в скобках (квадратных) показывается число элементов, а в VB-шных оно показывает верхнюю границу. Так что +1 делать не надо.

Объявление функции as long поставил. Но вот указатель на указатель.... это за гранью моего понимания :drunken:

А жаль. Это классная (но опасная) вещь. Именно из-за её опасности её не добавили в VB.

Код: Выделить всё
    Dim Check_Status_Ptr() As tagCheck_Status
    ReDim Check_Status_Ptr(0)
    check_file_sign App.Path & "\1.txt", Count, Check_Status_Ptr(0)

Ну это бред. Крайтчайший способ придать смысл — передать в качестве третьего переменного пустую Long-переменную, в неё вернётся адрес первого элемента массива.

* Добавлено ещё позже
Хм... Получил в NameParam крякозяблу типа ?Ы. Мысль - либо как то криво сработало и я структурой попал на левые данные, либо это Unicode.

Функция ждала: адрес переменной-указателя, чтобы записать в неё указатель на первый элемент массива.
Функция получила вместого этого: адрес первого элемента VB-массива, но, ничего не подозревая, записала по этому адресу адрес собственного массива.
Так что кракозябра в NameParam — не более чем адрес того массива, с которым ты должен работать. Если, опять же, передать в качестве третьего параметра адрес правильного поля из SA-дескриптора, то VB-массив будет "промапплен" на массив, созданный внутри функции.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение ALX_2002 » 03.03.2009 (Вт) 13:57

2 jangle: Да я бы с радостью ! ( Но проблема в том, что wbotho.dll не работоспособен отдельно от всего остального комплекса. Уже проверял при переносе на другую машину. При попытке обращение пишет банально - "wbotho.dll не найден.". Какая то глупая защита вербы.

2 Хакер: попробывал подсунуть Long переменную. Получил вполне адекватное значение адреса массива. Теперь озадачен вопросом - что за правильное поле из SA-дескриптора ? И как его передать ? :roll:

P.S Пока что почитаю мануал по ссылке. :drunken:

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение Хакер » 03.03.2009 (Вт) 14:07

Теперь озадачен вопросом - что за правильное поле из SA-дескриптора ? И как его передать ?


Я для кого писал:
3) А ещё можно объявить VB-дин-массив, получить его SA-дескриптор, и в функцию передать в качестве второго параметра: адрес SA.cbElements, а в качестве третьего: адрес SA.pvData.

:?:
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение ALX_2002 » 03.03.2009 (Вт) 14:11

:shock: Виноват. Сосредоточился на конечных сообщениях. Про начало и забыл совсем. :) Ушёл изучать. Пока только не понял, что такое SA.cbElements и SA.pvData. Пошёл искать в мануале и вникать. :)

* Добавлено

Почитал мануал. Многое непонятно. Где брать SA дескриптор так и не въехал. И что собой представляет cbElements и pvData так и не ясно :(

* Хм....

Поискал в нете.

http://officegoodies.wiki.sourceforge.net/VBArrayColumns
SA - SafeArray.

Нашёл структуру.

Код: Выделить всё
Private Type SafeArray1D
    cDims As Integer
    fFeatures As Integer
    cbElements As Long
    cLocks As Long
    pvData As Long
    Bounds(0 To 0) As SafeArrayBound
End Type


По прежнему понимания как это всё соединить - нет :shock:

Viper
Артефакт VBStreets
Артефакт VBStreets
Аватара пользователя
 
Сообщения: 4394
Зарегистрирован: 12.04.2005 (Вт) 17:50
Откуда: Н.Новгород

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение Viper » 03.03.2009 (Вт) 15:10

В "кирпичах" ажно два "кирпича" для работы с SAFEARRAY
Весь мир матрица, а мы в нем потоки байтов!

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение Хакер » 03.03.2009 (Вт) 15:14

Почитал мануал. (...) Где брать SA дескриптор так и не въехал. И что собой представляет cbElements и pvData так и не ясно

Странная логика.
Я рассказал о трёх способах, но интересуют нас последние два.

Логично, что если я выделяю решение как отдельный способ, то такие решения сильно отличаются друг от друга. Так, надо полагать, что способ 2 сильно отличается от способа 3, или даже вообще не имеет с ним ничего общего.

Про трюк я говорил во втором способе:
2) Перейти на мой трюк, получив возможность в VB объявлять указатели. Тогда всё существенно проще.

И во втором способе я не говорил ни слова о SA-дескрипторе.
Чтобы применять трюк, надо было читать статью. Логично, что в статье ничего содержалось о SA-дескрипторах, потому что она не о них, а о реализации указателей в VB.

И есть третий способ, основанный на правке полей SA-дескриптора:
3) А ещё можно объявить VB-дин-массив, получить его SA-дескриптор, и в функцию передать в качестве второго параметра: адрес SA.cbElements, а в качестве третьего: адрес SA.pvData.

Но в этом способе нет ни капельки того, о чём написано в статье, т.е. в нём никак не применяется пресловутый "трюк".

Это разные способы. Отправил читать статью я тебя затем, чтобы ты освоил трюк. Ты же искал в ней информацию о SA-дескрипторах.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение Хакер » 03.03.2009 (Вт) 15:25

Ошибочка: не cbElements, а cElements (при твоём объявлении это поле внутри Bounds(0)).
А в cbElements надо записать sizeof(Check_Status).

http://officegoodies.wiki.sourceforge.net/VBArrayColumns

Ерунда. У GSerg'а лучше написано.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение ALX_2002 » 03.03.2009 (Вт) 15:35

2 Хакер:
О боги.... С каждой минутой только хуже... Я поэтому и спросил - какой метод лучше использовать - какой из них наиболее прост. Потому что с таким использованием VB сталкиваюсь первый раз. :shock: По ощущением напоминает, как человеку освоившему велосипед начинают рассказывать как управлять космическим кораблём и предлагают решить на каком топливе он хочет полететь. :cyclops: .

Ошибочка: не cbElements, а cElements (при твоём объявлении это поле внутри Bounds(0)).
А в cbElements надо записать sizeof(Check_Status).


Вот это вообще не понял :shock: При каком моём объявлении... ?

Мануал про указатели посмотрел, статья GSerg (http://www.vbstreets.ru/VB/Articles/65977.aspx) я так понимаю эта... ?

А пример какой нить маломальски ясный можно ? :shock: А то уже моск кипит.

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение ALX_2002 » 04.03.2009 (Ср) 11:06

Ммм. С примером уже сложнее. :) Ясно. Статью посмотрел - то что разобрано там в общих чертах понятно. Но как сделать это с учётом структуры tagCheck_Status пока не въезжаю. :cyclops:

2 Хакер:
2) Перейти на мой трюк, получив возможность в VB объявлять указатели. Тогда всё существенно проще.

Можно чуть подробнее - как мне перейти на указатели ?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение Хакер » 04.03.2009 (Ср) 12:05

Пример с указателями:

Код: Выделить всё
Private Declare Function check_file_sign Lib "wbotho.dll" (ByVal file_name As String, ByRef Count As Byte, ByVal PointerToPointerToChStArray As Long) As Long

Public Type tagCheck_Status
    NameParam(12) As Byte
    Alias(120) As Byte
    Position As Byte
    Status As Byte
    Date As Long
End Type

Public Sub foo(ByRef PtrToChSt As tagCheck_Status, ByRef PtrToPtrToChSt As Long, Optional ByVal PtrBase As Long)
    Dim lCount      As Long
    Dim i           As Long
   
    PtrBase = VarPtr(PtrBase)
   
   
    PutMem4 PtrBase - 4, PtrBase - 8 ' PtrToPtrToChSt у нас будет указателем на PtrToChSt
   
    error_code = check_file_sign(App.Path & "\27911469.KVT", lCount, PtrBase - 8)
    For i = 0 To lCount - 1
        Debug.Print StrConv(PtrToChSt.NameParam, vbUnicode)
       
        ' Сдвигаем указатель на следующую запись
        PtrToPtrToChSt = PtrToPtrToChSt + Len(PtrToChSt)  ' А в сях: PtrToChSt++
    Next i
   
    ' Тут надо вызвать FreeMemory, передав PtrToPtrToChSt - Len(PtrToChSt )*lCount
End Sub
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение ALX_2002 » 04.03.2009 (Ср) 14:40

2 Хакер: Земной поклон. ) Всё заработало. Сейчас только обвязку сделаю, чтоб наружу из COM объекта выдавать массив структур и можно считать, что ДЕНЬ УДАЛСЯ :) Огромное спасибо !!!

P.S Одно расстраивает - как работает и что делает код

Код: Выделить всё
PtrBase = VarPtr(PtrBase)
   'Stop
   
PutMem4 PtrBase - 4, PtrBase - 8


так и не понял :oops: Буду вникать )

* Добавлено

По ходу начал вникать... PtrBase нужен для получения "точки отсчёта", а -4 это смещение до второго параметра, и -8 до первого ? :|

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение ALX_2002 » 05.03.2009 (Чт) 10:22

2 Хакер: Ммм. Хотел уточнить на счёт FreeMemory. Думал что это как раз не вызовёт никаких проблем, но у упёрся в то, что не смог найти её объявление :scratch:. Я так понял это встроенная функция для C, а для VB нужно что то другое использовать. Типа GlobalFree ?

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение Хакер » 05.03.2009 (Чт) 11:06

PtrBase нужен для получения "точки отсчёта", а -4 это смещение до второго параметра, и -8 до первого ?

Да, потому получить иными способами адрес ByRef-аргумента в стеке нельзя. Могу рассказать почему.

Я так понял это встроенная функция для C, а для VB нужно что то другое использовать. Типа GlobalFree ?

А я так понял, что это функция той же библиотеки.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение ALX_2002 » 05.03.2009 (Чт) 11:59

1)
Да, потому получить иными способами адрес ByRef-аргумента в стеке нельзя. Могу рассказать почему.

С огромным удовольствием послушаю или почитаю ! Въехать в процесс для меня важнее чем просто тупо воспользоваться готовой функцией. :)

2) :shock: Действительно - нашёл в описании библы
Для освобождения памяти, которая была выделена для работы некоторых функций 16-разрядныой библиотеки, служит функция FreeMemory(wbotho, wsigno), которая имеет прототип:
void WINAPI FreeMemory (void *lpMemory);
Параметр:
(i) lpMemory — указатель на блок памяти, который необходимо освободить.
Пример использования функции FreeMemory:
Check_Status_Ptr status_array;
...
FreeMemory (status_array);


Надеюсь правильно интерпретировал :scratch:
Код: Выделить всё
Private Declare Function FreeMemoryA Lib "wbotho.dll" Alias "FreeMemory" (ByRef lpMemory As Long)

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение Хакер » 05.03.2009 (Чт) 14:41

ALX_2002 писал(а):Надеюсь правильно интерпретировал
Код: Выделить всё
Private Declare Function FreeMemoryA Lib "wbotho.dll" Alias "FreeMemory" (ByRef lpMemory As Long)

Нет.

ByRef lpMem As tagStatus_Check
или
ByVal lpMem As Long


С огромным удовольствием послушаю или почитаю ! Въехать в процесс для меня важнее чем просто тупо воспользоваться готовой функцией.

Представим себе, что VB компилирует на сразу, а переводит VB-код с C-style-код.

В сях есть два унарных оператора: * и &.
*xxx — значит (грубо) "то, что лежит по адресу, хранящемуся в xxx"
*123 — значит (грубо) "то, что лежит по адресу 123".
В отрыве от типа указателя такая запись имеет мало смысла (потому что компилятор не знает, а что должно лежать по адресу), но если xxx имеет правильный тип, то запись обретает смысл.
В частоности, по записи [/icode]*123[/icode] совершенно непонятно, идёт л речь о байте, лежащем по адресу 123, или же о структуре, лежащей по адресу 123. О чём идёт речь компилятор понимает, как я уже сказал, по типу операнда, поэтому достаточно скастовать операнд к правильному указательному типу, чтобы смысл возник:
Выражение *( (char*)123) будет иметь смысл "байт, лежащий по адресу 123". Замечу, что * — это такой же унарный оператор как например - (минус), т.е. точно также, как можно писать "-a" или -(a)[icode] или даже [icode]-(((a))), точно также абсолютно допустимой будет запись *a, *(a) или даже *(((a))).

Так что вообще говоря, оператор * принимает в качестве операнда не адрес, а указатель. Так что если foo имеет тип "long*", то *(foo) и *(foo+1) обратятся к лонгам, отстающим в памяти друг от друга не на 1 байт, а на 1*sizeof(long). О как! :)

Кстати в сях aaaaa[bbbb] всего лишь означает *(aaaa + bbbb)

Другой оператор & — возвращает указатель (типа указатель на некоторыйтип), приняв в качестве аргумента выражение некотороготипа.

Очевидно, что & и * — взаимообратны друг другу примерно так же, как [синус и арксинус] или [возведение в квадрат и квадратный корень].

Поэтому они "взаимоуничтожают" друг-друга, так что *(&(fooo)) эквивалентно просто fooo. Для примера: совершенно очевидно, что &(*(123)) будет 123, потому как "адрес того, что лежит по адресу 123" будет 123.

Но опять же замечаю: * принимает не адрес, а указатель. & возвращает не адрес, а указатель.
Важно понимать, что указатель и адрес — разные вещи.

Закончили ликбез по сишный прелестям.

Так вот: в VB нет указателей, доступных пользователю, а значит нет и указательный типов (понятие "тип переменной/выражения" в VB гораздо уже, чем оно в С/С++), нет операторов, способных либо принять указатель на что-то и отдать это что-то, либо принять что-то и вернуть указатель на это что-то. (Но сами по себе указатели в VB есть, потому что их не может не быть при наличии хотя бы возможности передать что-то ByRef.)

Так вот, поскольку всего этого в VB нет, проиллюстрировать придётся на сишном примере.

Представим, что VB-компилятор не сразу же компилирует VB-код, а переводит его в сишный.
Рассматривать будем аргументы функций, имеющие тип long (потому что с более сложными всё обстоит несколько иначе).

В объявлении функцииByVal foo As Long эквивалентно сишному long foo.
В объявлении функцииByRef foo As Long эквивалентно сишному long* foo.

В коде функции, имеющей ByVal-аргумент "foo", всякое упоминание этого аргумента, то есть foo, эквивалентно сишному foo
В коде функции, имеющей ByRef-аргумент "foo", всякое упоминание этого аргумента, то есть такое же foo, будет в сях эквивалентно *foo

В коде функций, при вызове другой функции, когда что-то передаётся в качестве аргумента, и при том в "другой функции" этот аргумент ByRef-ный, то в сишном эквиваленте перед этим "что-то" будет стоять оператор &.

Вот такие правила. Теперь несколько примеров:
VB:
Код: Выделить всё
Sub Alpha(ByVal AA As Long, ByRef BB As Long)
    Dim CC As Long
    Dim DD As Long
   
    CC = AA
    DD = BB

    Omega AA, BB, CC, DD
End Sub

Sub Omega(ByVal param1 As Long, ByVal param2 As Long, ByRef param3 As Long, ByRef param4 As Long)
     SomeOtherSub param1
     SomeOtherSub param2
     SomeOtherSub param3
     SomeOtherSub param4
End Sub

Sub SomeOtherSub (ByVal xyz As Long)
    ...
End Sub


С++:
Код: Выделить всё
void Alpha(long AA, long* BB)
{
    long CC;
    long DD;

    CC = AA;
    DD = *BB;

    Omega(AA, *BB, &CC, &DD);
}

void Omega(long param1, long param2, long* param3, long* param4)
{
    SomeOtherSub(param1);
    SomeOtherSub(param2);
    SomeOhterSub(*param3);
    SomeOtherSub(*param4);
}

void SomeOtherSub(long xyz)
{
  ...
}


Теперь смотри то на эти два куска кода, то на правила "перевода" VB-кода в сишный.

Вот ещё один пример:
VB:
Код: Выделить всё
Sub Ebru(ByVal xxx As Long, ByRef yyy As Long)
     Kaya xxx, yyy, xxx, yyy
End Sub

Sub Kaya(ByVal aaa As Long, ByVal bbb As Long, ByRef ccc As Long, ByRef ddd As Long)
     ...
End Sub


C++:
Код: Выделить всё
void Ebru(long xxx, long* yyy)
{
     Kaya(xxx, *yyy, &(xxx), &(*yyy) );  // Здесь последнее &(*yyy) упрощается до yyy
}

void Kaya(long aaa, long bbb, long* ccc, long* ddd)
{
      ...
}


Т.е. смотри: у нас в Ebru в yyy — ByRef и в Kaya аргумент ddd — тоже ByRef. Поэтому выполняется сразу два правила "упоминание ByRef-аргумента" и "передача чего бы то ни было в качестве ByRef-аргумента". Поэтому добавляется и *, и &, которые взаимоуничтожают друг-друга.


Но многим требовалась в VB возможность всё-таки получить адрес, поэтому был сделан следующий трюк: создана функция VarPtr, которая просто возвращает число, которое её передали. Т.е. на самом деле функция объявлена так:
Код: Выделить всё
Function VarPtr (ByVal foo As Long)
    VarPtr = foo
End Sub

или, если на С++:
Код: Выделить всё
long VarPtr(long foo)
{
    return foo;
}

Но VB заставили (нарочно неправильно объявив в TLB) думать, что VarPtr объявлена так:
Код: Выделить всё
Function VarPtr(ByRef xxx As Any) As Long


Поэтому, когда мы пишем:
Код: Выделить всё
Sub Russia(ByVal SomeParam As Long)
  Dim SomeVar As Long

  dim a as long
  dim b as long

  a = VarPtr(SomeParam)
  b = VarPtr(SomeVar)
End Sub


То это эквивалентно:
Код: Выделить всё
void Russia(long SomeParam)
{
      long SomeVar;
   
      long a, b;

      a = VarPtr(&SomeParam);
      b = VarPtr(&SomeVar);
}

long VarPtr(void* something)    // Так себе представляет функцию VB
long VarPtr(long something) {return something;} // Такая она на самом деле


Как видишь, срабатывает правило "передаём <что-то> в другую функцию, имеющую ByRef-аргумент — добавляем & перед <чем-то>".

Учитывая то, что VarPtr возвращает то же, можно считать, что её вообще нет в коде (если её действительно убрать из кода, то будет a = &SomeParam; и a = &SomeVar; — что неправильно с точки зрения сей, потому как переменная SomeVar имеет тип "long", тогда выражение &SomeVar имеет тип "long*", и получается, что мы пытаемся присвоить значение одного ("long*") типа переменной другого (просто "long") типа, чего делать нельзя, не скастовав выражение к типу "long").

Теперь смотри что случится, когда мы в VarPtr передадим ByRef-аргумент:
VB:
Код: Выделить всё
Sub Main()
    Dim CoolVariable As Long
    CoolVariable = 777
   
    FirstAction CoolVariable
End Sub

Sub FirstAction(ByRef xxx As Long)
      SecondActionAction xxx
End Sub

Sub SecondActionAction(ByRef xxx As Long)
      ThirdAction xxx
End Sub

Sub ThirdAction(ByRef dunduck As Long)
     Dim result As Long
     result = VarPtr(xxx) ' И вот тут мы вдруг захотели получить адрес аргумента dunduck
End Sub

в С++:
Код: Выделить всё
void Main()
{
    long CoolVariable;
    CoolVariable = 777;
   
    FirstAction(&CoolVariable);
}

void FirstAction(long* xxx)
{
      SecondActionAction(&(*xxx));
}

void SecondActionAction(long* xxx)
{
      ThirdAction(&(*xxx));
}

void ThirdAction(long* dunduck)
{
     long result;
     result = VarPtr(&(*dunduck))
}

Тут мы видим, что кроме первого правила, сработало ещё и второе "всякое упоминание ByRef-аргумента abc внутри функции выглядит как *abc".

С учётом того, что половина упрощается:
Код: Выделить всё
void Main()
{
    long CoolVariable;
    CoolVariable = 777;
   
    FirstAction(&CoolVariable);
}

void FirstAction(long* xxx)
{
      SecondActionAction(xxx);
}

void SecondActionAction(long* xxx)
{
      ThirdAction(xxx);
}

void ThirdAction(long* dunduck)
{
     long result;
     result = VarPtr(dunduck)
}


Так вот, рассмотрим, что у нас происходит.
1) В переменную CoolVariable записывается 777.
2) Выражение &CoolVariable "вычисляется". Результатом его вычисления является указатель на переменную CoolVariable, в которой лежит 777.
3) Этот указатель на переменную CoolVariable, в которой лежит 777, передаётся в FirstAction.
4) FirstAction ничего с этим указателем (на CoolVariable, в которой 777) не делает, передаёт его в SecondAction.
5) SecondAction ничего с этим указателем (на CoolVariable, в которой 777) не делает, передаёт его в ThirdAction.
6) ThirdAction принимает указатель на CoolVariable, в которой лежит 777, ничего с этим указателем не далает, передаёт его в VarPtr.
7) В VarPtr передаётся этот указатель, а фактически (физически) — адрес переменной CoolVariable. По этому адресу в памяти лежит число 777.
8) VarPtr тупо возвращает этот адрес как обычное число.
9) Этот адрес, как обычное число, записывается в long-переменную result.

В итоге: в переменной result у нас получается не адрес аргумента "dunduck", а адрес переменной SecondAction.

Так что с помощью VarPtr невозможно никакими трюками получить адрес ByRef-аргумента — всегда будешь получать его физическое значение.


(Пора бы завязыватьс с этой графоманией. На написание ответов трачу слишком много времени :( )
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

ALX_2002
Мега гуру
Мега гуру
 
Сообщения: 2054
Зарегистрирован: 25.11.2002 (Пн) 20:03

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение ALX_2002 » 05.03.2009 (Чт) 15:49

Мда..... Моему мозгу такой механизм понять тяжеловато... :shock: Слишком привык к объектным моделям. Пока что понял где то 5% от всего написанного. Сейчас распечатаю - в метро почитаю. :o

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение Хакер » 05.03.2009 (Чт) 15:52

Человеку, видавшему только VB, понять смысл указателей и то, как ими пользоваться, всё равно что человеку, знающему только русский язык, понять смысл английских артиклей (a, the) и научиться ими правильно пользоваться.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение alibek » 05.03.2009 (Чт) 16:23

Хакер писал(а):Человеку, видавшему только VB, понять смысл указателей и то, как ими пользоваться, всё равно что человеку, знающему только русский язык, понять смысл английских артиклей (a, the) и научиться ими правильно пользоваться.

Зачем усложнять?

ALX_2002, для простоты картины, пока считай, что указатель — это что-то типа CallByName Me, sProcPtr, VbMethod, где sProcPtr — текстовая переменная, содержащая имя метода.
А указатель на указатель — CallByName Me, CallByName(Me, sPtr, VbMethod), VbMethod, здесь sPtr — имя метода (функции), который вернет имя метода, который нужно вызвать.
Тут много неправильного (про указатели), но это поможет с ними освоится и их понять.
Lasciate ogni speranza, voi ch'entrate.

Хакер
Телепат
Телепат
Аватара пользователя
 
Сообщения: 16478
Зарегистрирован: 13.11.2005 (Вс) 2:43
Откуда: Казахстан, Петропавловск

Re: Адаптация VB к Сишной библе. Не получается создать структуру

Сообщение Хакер » 05.03.2009 (Чт) 17:00

Зачем усложнять?

Твой пример-аналогия не демонстрирует очень многое из того, что есть в области указателей и является непонятным для большинства. А то, что демонстирует, мне кажется, большинству понятно.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 56

    TopList  
cron