Object из указателя

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

Object из указателя

Сообщение djalex777 » 22.03.2009 (Вс) 16:26

Как создать объект имея на него указатель в виде long переменной?

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Object из указателя

Сообщение djalex777 » 22.03.2009 (Вс) 16:37

Нашел ответ:
Код: Выделить всё
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Function ObjectFromPTR(ByVal ptr As Long) As Object
Dim obj As Object
CopyMemory obj, ptr, 4
Set SetObjectByPTR = obj
CopyMemory obj, 0&, 4
End Function

Есть ещё вариант с функцией CopyObject из msvbvm60.dll

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

Re: Object из указателя

Сообщение Хакер » 22.03.2009 (Вс) 17:55

Бред. Никак не создать.
Если ты имеешь указатель в виде long переменной, значит объект уже создан.

А код, который ты нашёл — вообще дрянь.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Object из указателя

Сообщение djalex777 » 22.03.2009 (Вс) 20:05

По-поводу создания объекта неправильно выразился, имел ввиду сделать так чтобы object ссылался на имеющийся указатель. А чем код плох и какой есть вариант?

SLIM
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1840
Зарегистрирован: 04.04.2008 (Пт) 18:21
Откуда: Краснодар

Re: Object из указателя

Сообщение SLIM » 22.03.2009 (Вс) 21:25

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

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

Re: Object из указателя

Сообщение jangle » 22.03.2009 (Вс) 21:50

По-поводу создания объекта неправильно выразился, имел ввиду сделать так чтобы object ссылался на имеющийся указатель. А чем код плох и какой есть вариант?


Ничем, приведенный тобой код совершенно правильный

SLIM писал(а):Первый вариант вопроса более вменяем чем второй.
Если первое невозможно, то второе уж точно


Иногда лучше жевать чем говорить, можно сойти за специалиста.

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

Re: Object из указателя

Сообщение Хакер » 22.03.2009 (Вс) 22:05

Вопрос, что первый, что второй — ерунда, но в этом редком случае, вобщем-то, понятно, что хотел автор.

Код плох сразу очень многим:
  • RtlMoveMemory(..., ..., 4) вместо GetMem4
  • Ещё раз RtlMoveMemory(..., ..., 4) вместо GetMem4
  • Set SetObjectByPTR = obj не должен вызывать QueryInterface для запроса IDispatch-интерфейса, потому что обе ссылки имеют один интерфейсно-указательный тип. Либо VB всё равно вызывает QueryInterface, либо тебе просто везёт, потому что то число, которые ты получаешь — уже и так указатель на интерфейс IDispatch (и если вдруг это будет указателем на др. интерфейс, не унаследованный от IDispatch, то твой код приведёт к непредсказуемым последствиям).
  • Автор этого кода по совокупности вышесказанного — дятел. Он кодер, механический кодер, который просто использует подсмотренные где-то приёмы, но ему глубоко фиолетово, как оно работает изнутри1.

Вместо всего этого гадостного кода будет достаточно альтернативно-объявленной VarPtr:
Код: Выделить всё
Private Declare Function CastPtrToIUnknown Lib "msvbvm60.dll" Alias "VarPtr" (ByVal pUnk As Long) As IUnknown


Пример использования:
Код: Выделить всё
Private Sub Form_Load()
Dim PointerToFormInstance as long
PointerToFormInstance  = ObjPtr(Me)
CastPtrToIUnknown(PointerToFormInstance).Caption = "Привет!"
End Sub


А jangle'у похоже надо запретить писать в этот раздел.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

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

Re: Object из указателя

Сообщение jangle » 22.03.2009 (Вс) 22:26

Хакер писал(а):[*]Автор этого кода по совокупности вышесказанного — дятел. Он кодер, механический кодер, который просто использует подсмотренные где-то приёмы, но ему глубоко фиолетово, как оно работает изнутри1. [/list]


Автор того кода - Брюс Маккини, автор книги "Hardcore Visual Basic". У которого авторитет - больше чем у сотни Хакеров.
Код собственно их самой книги, у кого она есть в переводе, можете взглянуть.
Изображение

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

Re: Object из указателя

Сообщение Хакер » 22.03.2009 (Вс) 22:29

Авторитет у него может и больше, и рассказы у него душевные, но вот этот код его — лажа.

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

Vi
Постоялец
Постоялец
 
Сообщения: 739
Зарегистрирован: 25.01.2002 (Пт) 11:03
Откуда: Россия, Ижевск

Re: Object из указателя

Сообщение Vi » 23.03.2009 (Пн) 11:32

Хакер писал(а):Авторитет у него может и больше, и рассказы у него душевные, но вот этот код его — лажа.
Можно продолжить перечислять недостатки: его код нарушает соглашение COM относительно того, кто ответственнен за AddRef/Release-вызовы.

Хакер, а ты свой код проверял? У меня после закрытия окна с твоей Form_Load VB просто падает.

На самом деле, код, который привел djalex777 (с учетом замены SetObjectByPTR на правильное имя ObjectFromPTR), правильно считает ссылки. В то же время VarPtr и ObjPtr никаких ссылок не считает, и поэтому CastPtrToIUnknown возвращает неправильный объект с точки зрения счетчика ссылок.

PS
Многие знания умножают печали. Как-то так.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! (с) КВН

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

Re: Object из указателя

Сообщение Хакер » 23.03.2009 (Пн) 11:56

Vi, по соглашению: функция, которая принимает ссылку на объект и возвращает её же, не должна увеличивать счётчик у этого объекта. Моя не увеличивает. Это просто способ скастовать long к (IUnknown*). Всё остальное: вызов QI для получения нужного интерфейса, вызовы AddRef/Release будет сделано VB автоматически.

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

RayShade
Scarmarked
Scarmarked
Аватара пользователя
 
Сообщения: 5511
Зарегистрирован: 02.12.2002 (Пн) 17:11
Откуда: Russia, Saint-Petersburg

Re: Object из указателя

Сообщение RayShade » 23.03.2009 (Пн) 14:37

Да, науке известны многочисленные случаи падения IDE при попытках сделать на VB различные нетривиальные вещи :)
I don't understand. Sorry.

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

Re: Object из указателя

Сообщение jangle » 23.03.2009 (Пн) 14:51

RayShade писал(а):Да, науке известны многочисленные случаи падения IDE при попытках сделать на VB различные нетривиальные вещи :)


Ну ведь правильные программисты не роняют IDE, ведь правда RayShade? :alien:

Vi
Постоялец
Постоялец
 
Сообщения: 739
Зарегистрирован: 25.01.2002 (Пт) 11:03
Откуда: Россия, Ижевск

Re: Object из указателя

Сообщение Vi » 23.03.2009 (Пн) 14:51

Vi, по соглашению: функция, которая принимает ссылку на объект и возвращает её же, не должна увеличивать счётчик у этого объекта. Моя не увеличивает. Это просто способ скастовать long к (IUnknown*). Всё остальное: вызов QI для получения нужного интерфейса, вызовы AddRef/Release будет сделано VB автоматически.

Это неправда. Возвращаемый параметр для указателя на интерфейс должен ВСЕГДА иметь увеличенное значение счетчика.
***EDIT***
Либо, в качестве ранней оптимизации в твоем случае, входной параметр как значение Long должен быть объектом с увеличенной ссылкой, но твое ObjPtr(Me) им не является.
Код: Выделить всё
Private Declare Function CastPtrToIUnknown Lib "msvbvm60.dll" Alias "VarPtr" (ByVal pUnk As Long) As IUnknown

VarPtr
This function can be used to get the address of a variable or an array element. It takes the variable name or the array element as the parameter and returns the address. However, you should be aware that unlocked Dynamic Arrays may be reallocated by Visual Basic, so you must be very careful when you use VarPtr to get the address of an array element.

Использование VarPtr, возвращающее объект или интерфейс, неправильное, потому что VarPtr возвращает просто адрес переменной, но не увеличивает количество ссылок на объект. Но VB должен уничтожить возвращенный объект, и он его уничтожает.
То, что что-то падает, совсем не показатель того, что соглашение нарушено.

Именно поэтому. Ты попробуй не один раз вызвать, а несколько. Как правило, объект формы используется во многих местах и имеет счетчик достаточно большим, чтобы эффект имел место. Но рано или поздно счетчик обнулится, и объект саморазрушится, т.к. не будет иметь клиентов. Например, так:
Код: Выделить всё
  For i = 1 To 10
    CastPtrToIUnknown(PointerToFormInstance).Caption = "Привет" & i  & "!"
  Next
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! (с) КВН

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

Re: Object из указателя

Сообщение Viper » 23.03.2009 (Пн) 15:53

Можно посмотреть еще в эту сторону.
Весь мир матрица, а мы в нем потоки байтов!

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

Re: Object из указателя

Сообщение Хакер » 23.03.2009 (Пн) 15:57

Vi, я тебе скажу, откуда берётся крах. Крах берётся оттуда, что вызов ObjPtr происходит с нарушением COM-соглашения.

Это нарушение, заложенное в VB, плюс нарушение, заложенное в код jangle невилируют друг-друга.

CastPtrToIUnknown всего лишь кастует типы. Если бы в VB были кастования как в С/С++, проблемы бы не было вообще. Посколько это кастование, даже логически ясно, что никаких AddRef/Release вызовов быть не должно.

Я тебе напомню, насчёт соглашений:
  • Если мы передаём в функцию указатель на интерфейс, мы (а не функция) должны должны вызвать AddRef, перед тем, как передать.
  • Функция, принимающая в качестве одного из аргументов указатель на интерфейс, внутри себя сама должна вызвать Release, когда этот параметр ей больше не нужен.
  • Функция, если она возвращает указатель на интерфейс, сама внутри себя должна вызвать AddRef у интерфейса, указатель на который она возвращает.

Исходя их этого, наша функция должна сделать внутри себя один AddRef (правило №3), и один Release (правило №2). Есть такая вещь, как оптимизация AddRef/Release-вызовов. Это когда лишние пары вызовов устраняются. Вот здесь их тоже можно устранить.

На самом деле, я могу предоставить простой пример, показывающий, что моя вариант ничего не нарушает, а вариант jangle — делает лишний AddRef.

Хочешь?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

RayShade
Scarmarked
Scarmarked
Аватара пользователя
 
Сообщения: 5511
Зарегистрирован: 02.12.2002 (Пн) 17:11
Откуда: Russia, Saint-Petersburg

Re: Object из указателя

Сообщение RayShade » 23.03.2009 (Пн) 16:16

Я понимаю дискуссию примерно наполовину, но тоже хочу пример :)
I don't understand. Sorry.

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

Re: Object из указателя

Сообщение Хакер » 23.03.2009 (Пн) 16:40

Vi писал(а):Например, так:
Код: Выделить всё
  For i = 1 To 10
    CastPtrToIUnknown(PointerToFormInstance).Caption = "Привет" & i  & "!"
  Next

Упадёт. Не потому, что CastPtrToIUnknown крива от природы, а потому что ты нарушил правило №1 (см. мой пост выше).

У тебя одна ссылка остаётся в переменной PointerToFormInstance, а вторую ссылку (ты её порождаешь) ты передаёшь в функцию. Таким образом ты должен был перед вызовом CastPtrToIUnknown сделать IUnknown::AddRef. Только не говори мне, что за тебя это может (и не дай бог не говори "должна сделать") сделать сама функция CastPtrToIUnknown и что в варианте jangle так и происходит. Это будет нарушение соглашений COM. Это будет нарушение правила номер два.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Vi
Постоялец
Постоялец
 
Сообщения: 739
Зарегистрирован: 25.01.2002 (Пт) 11:03
Откуда: Россия, Ижевск

Re: Object из указателя

Сообщение Vi » 23.03.2009 (Пн) 17:11

Хакер писал(а):Vi, я тебе скажу, откуда берётся крах. Крах берётся оттуда, что вызов ObjPtr происходит с нарушением COM-соглашения.

Т.е. твой пример ошибочен и не должен был появиться в качестве примера. Или был должен явно указать допущения и предположения.
Хакер писал(а):Это нарушение, заложенное в VB, плюс нарушение, заложенное в код jangle невилируют друг-друга.

Не соглашусь. ObjPtr (Function ObjPtr(Ptr As Unknown) As Long) и VarPtr (Function VarPtr(Ptr As Any) As Long) ничего не нарушают, и, тем более, нарушения не заложены в VB. Нарушают те, кто используют эти функции не по своему назначению. Эти функции возвращают адрес, причем они являются недокументированными (или отчасти документированными).
Хакер писал(а):CastPtrToIUnknown всего лишь кастует типы. Если бы в VB были кастования как в С/С++, проблемы бы не было вообще. Посколько это кастование, даже логически ясно, что никаких AddRef/Release вызовов быть не должно.

Я бы согласился здесь с тобой, но нужно указывать тот факт, что после использования переменной типа Long в качестве параметра функции CastPtrToIUnknown эта переменная содержит неверные данные и не должна быть использована в дальнейшем. Т.е. получается, что "кастирование" могло бы иметь место, но имеет место "кастрирование" переменной. Т.е. нельзя использовать CastPtrToIUnknown(PointerToFormInstance) с последующим CastPtrToIUnknown(PointerToFormInstance), а нужно перекидывать значение в объектную переменную Set pInstanceObject = CastPtrToIUnknown(PointerToFormInstance) и сразу же PointerToFormInstance = 0, чтобы не было соблазна его использовать.
Хакер писал(а):Функция, принимающая в качестве одного из аргументов указатель на интерфейс, внутри себя сама должна вызвать Release, когда этот параметр ей больше не нужен.

С другими двумя соглашусь, но вот это неверно. Аргументы функции никогда не могут быть от-Release-ны внутри функции. НИКОГДА. Просто потому, что он, переданный указатель, используется во внешнем коде, про который функция не может и не должна делать никаких предположений.
Хакер писал(а):На самом деле, я могу предоставить простой пример, показывающий, что мой вариант ничего не нарушает, а вариант jangle — делает лишний AddRef.Хочешь?

Лишний AddRef, он в самом получении указателя на интерфейс в виде Long там, где должен быть Object-ом или Unknown-ом. Естественно, что этот объект должен быть уничтожен как-то, но это не имеет отношения к нашей дискуссии.

***EDIT***
Удалил PS
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! (с) КВН

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

Re: Object из указателя

Сообщение jangle » 23.03.2009 (Пн) 17:23

Vi писал(а):С другими двумя соглашусь, но вот это неверно. Аргументы функции никогда не могут быть от-Release-ны внутри функции. НИКОГДА. Просто потому, что он, переданный указатель, используется во внешнем коде, про который функция не может и не должна делать никаких предположений.


Вот именно, я тоже это заметил. Хакер хочет релизить указатель, который был создан вне этой функции, а ведь там "вовне" его ждет свой Release...

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

Re: Object из указателя

Сообщение Хакер » 23.03.2009 (Пн) 17:43

Т.е. твой пример ошибочен и не должен был появиться в качестве примера. Или был должен явно указать допущения и предположения.

Мой пример ни разу не ошибоычный.
Поясню.
Я просто убрал пару комплементарных вызовов AddRef/Release. Это допускается, это поощряемая техника оптимизации. И я убрал их в целях оптимизации и упрощения кода.

Я мог бы их не убирать, тогда мой пример выглядел бы так:
Код: Выделить всё
AddRef(PointerToFormInstance): CastPtrToIUnknown(PointerToFormInstance).Caption = "Привет!"

Release(PointerToFormInstance)


Тогда, если заключить CastPtrToIUnknown в цикл хоть из тысячи операций (у тебя было 10), ничего падать не будет:
Код: Выделить всё
For i = 1 to 1000
     AddRef(PointerToFormInstance): CastPtrToIUnknown(PointerToFormInstance).Caption = "Привет!"
Next i

Release(PointerToFormInstance)


Т.е. почему у тебя был крах в твоём примере с циклом: я убрал пару AddRef/Release, потому что можно было, потому что это была комплементарная пара. У тебя нет никакой компл. пары, так что AddRef/Release должны быть там, где должны: AddRef перед каждой передачей PointerToFormInstance в CastPtrToIUnknown — потому что правило №1, Release в конце Form_Load, потому что правило № 2 (оно распространяется не только на параметры функции, но и на лок. параменные, потому что они имеют одинаковую природу).

Уверяю тебя, что если бы ты не нарушил соглашений, ничего бы не падало. Моя функция здесь не причём.




Не соглашусь. ObjPtr (Function ObjPtr(Ptr As Unknown) As Long) и VarPtr (Function VarPtr(Ptr As Any) As Long) ничего не нарушают, и, тем более, нарушения не заложены в VB. Нарушают те, кто используют эти функции не по своему назначению. Эти функции возвращают адрес, причем они являются недокументированными (или отчасти документированными).

А я говорю: нарушения есть. Про VarPtr я ничего не говорил, с ней всё ок.
Но вот когда VB-компилятор генерирует call-фрейм для функции ObjPtr с передачей в неё переменной, он не генерирует вызова AddRef для этой переменной, хотя по соглашению — должен (правило № 1). И сделано так авторами VB-компилятор не по ошибке, они были вынуждены так сделать (могу объяснить почему).

У ObjPtr параметр Ptr ByVal-ный, если что.

Я бы согласился здесь с тобой, но нужно указывать тот факт, что после использования переменной типа Long в качестве параметра функции CastPtrToIUnknown эта переменная содержит неверные данные и не должна быть использована в дальнейшем.

Ерунда. Откуда там взяться неверным данным?
1) Там хранится указатель на объект. Валидный указатель на живой (валидный) объект.
2) Физически изменить эту переменную ни ObjPtr-функция, ни кто-либо другой не может. Значит что до, что после вызова ObjPtr в этой переменной будет одно и то же валидное значение.
3) На что ты тогда намекаешь? На то, что после вызова ObjPtr невалидным будет сам объект (т.е. умрёт?). Он не не должен умереть. Он и не умрёт. У тебя он умирает, потому что ты забываешь делать AddRef перед вызовом CastPtrToIUnknown, а должен.

Т.е. нельзя использовать CastPtrToIUnknown(PointerToFormInstance) с последующим CastPtrToIUnknown(PointerToFormInstance), а нужно перекидывать значение в объектную переменную Set pInstanceObject = CastPtrToIUnknown(PointerToFormInstance) и сразу же PointerToFormInstance = 0, чтобы не было соблазна его использовать.

Если насильно заставить себя нарушать соглашение (правило номер один), то то, что я отцитировал — один из способов выкрутиться из ситуации. Да, действительно, нарушая соглашения, не делая AddRef тогда, когда нужно, придётся делать то, что ты написал. Но если не нарушать соглашение, то всё ОК.



Ещё раз, отвелчённо:
VB-шное:
Код: Выделить всё
CastPtrToIUnknown(...)

эквивалентном сипипишному:
Код: Выделить всё
(IUnknown*)(...)


Ты действительно считаешь, что статическое кастование должно повлечь вызов AddRef? Считаешь?
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

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

Re: Object из указателя

Сообщение jangle » 23.03.2009 (Пн) 17:44

RayShade писал(а):Я понимаю дискуссию примерно наполовину, но тоже хочу пример :)


Вот пример с ВБакселератора, думаю там все понятно. А Хакер - просто оказался в плену своих заблуждений.
Кстати код ObjectFromPtr используется во всех контролах www.vbaccelerator.com
Никаких проблем с этими контролами нету, народ их юзают уже много лет.
Вложения
objstore.zip
(25.25 Кб) Скачиваний: 54

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

Re: Object из указателя

Сообщение Хакер » 23.03.2009 (Пн) 17:49

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

djalex777
Постоялец
Постоялец
 
Сообщения: 461
Зарегистрирован: 23.03.2006 (Чт) 16:02

Re: Object из указателя

Сообщение djalex777 » 23.03.2009 (Пн) 17:51

Вот вариант c GetMemObj:
Код: Выделить всё
Private Declare Sub GetMemObj Lib "MSVBVM60.DLL"  (ByRef src As Long,ByRef dst As Object)
...
'Использование
Dim obj As Object
GetMemObj object_ptr, obj
obj.caption = "hello"
...

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

Re: Object из указателя

Сообщение jangle » 23.03.2009 (Пн) 17:55

Хакер писал(а):VBAccelerator — огромный рассадник быдлокода... тоже мне, нашёл авторитетный источник.


Да ладно, нормальные контролы. Используют их тысячи программистов. Любые глюки давно бы пофиксели. Опенсоурс же.

И кстати статья по нашей теме, как раз с нелюбимым тобой Bruce McKinney's и ObjectFromPtr
http://www.vbaccelerator.com/codelib/im ... jstore.htm

Vi
Постоялец
Постоялец
 
Сообщения: 739
Зарегистрирован: 25.01.2002 (Пт) 11:03
Откуда: Россия, Ижевск

Re: Object из указателя

Сообщение Vi » 23.03.2009 (Пн) 22:06

Хакер писал(а):Мой пример ни разу не ошибоычный.Поясню.Я просто убрал пару комплементарных вызовов AddRef/Release. Это допускается, это поощряемая техника оптимизации. И я убрал их в целях оптимизации и упрощения кода.
Я мог бы их не убирать, тогда мой пример выглядел бы так:
Код: Выделить всё
AddRef(PointerToFormInstance): CastPtrToIUnknown(PointerToFormInstance).Caption = "Привет!"
Release(PointerToFormInstance)

Если в PointerToFormInstance имеется ввиду ObjPtr(Me), то снова неверно. А почему? А потому что ты неверно затвердил "соглашения СОМ", хотя, чувствуется, понятие есть. У меня сейчас нет выхода на MSDN, если нужно, я скопирую из Спецификации СОМ.

Начнем с того, что параметры в СОМ могут быть [in], [in,out] и [out,retval] и пусть они будут типа Object. Т.е. Function GetObj(ByVal In As Object, ByRef InOut As Object) As Object. Параметр In и pInOut есть параметры [in] и [in,out] соответственно; значение, которое возвращает функция и есть параметр [out,retval].

СОМ утверждает, что владельцем параметров как in, так и out является клиент или вызывающий функцию. В случае параметра [in,out] или ByRef функция может изменить значение, освободив старое через Release и назначив новое с использованием AddRef.
Хакер писал(а):Я тебе напомню, насчёт соглашений:
1) Если мы передаём в функцию указатель на интерфейс, мы (а не функция) должны должны вызвать AddRef, перед тем, как передать.
2) Функция, принимающая в качестве одного из аргументов указатель на интерфейс, внутри себя сама должна вызвать Release, когда этот параметр ей больше не нужен.
3) Функция, если она возвращает указатель на интерфейс, сама внутри себя должна вызвать AddRef у интерфейса, указатель на который она возвращает.

Итак твои пункты.
1) Чтобы использовать указатель, его счетчик ссылок (далее N) должен быть больше 0 вне зависимости от того, кто и когда вызвал эти увеличенные ссылки. И в этом плане использование ObjPtr(Me) есть правильное использование как в параметре Me, т.к. он реально уже существует, т.е. его N>=1, так и ObjPtr(Me) как целое число, хранящее указатель на объект Me. Единственное, ObjPtr(Me) не является полноценной ссылкой на объект Me, но это видно из ее типа.
2) Очевидно, что функция может вызвать Release только на объекте [in,out] или ByRef. Других оснований для Release нет и быть не может.
(Только для VB с его отсутствием явного обращения к счетчику ссылок, но не для СОМ) Либо ты должен написать комментарий, что функция принимает Long в качестве входного и неизменяемого значения, но реально функция, чтобы не заморачиваться с Object или при невозможности такого заморачивания, считает, что параметр фактически изменяемый и после вызова функции переменная, используемая для этого параметра, либо не должна использоваться, либо должна быть обнулена. (Прим. ни ObjPtr, ни VarPtr не являются такой функцией.)
3) Тут полностью соглашусь: возвращаемые указатели на интерфейс должна быть про-AddRef-лены. (Прим. ни ObjPtr, ни VarPtr не являются такой функцией - они не возвращают указатель.)

Код: Выделить всё
PointerToFormInstance = ObjPtr(Me) ' функция не возвращает объект, поэтому никаких AddRef нет и быть не может  N = n
For i = 1 to 1000
     Dim PointerToFormInstance2 As Long
     PointerToFormInstance2 = PointerToFormInstance: AddRef(PointerToFormInstance2) ' для Release после CastPtrToIUnknown N = n+1
     CastPtrToIUnknown(PointerToFormInstance2).Caption = "Привет!" ' N = n+1-1 = n
Next i
' соответственно для Release(PointerToFormInstance) повода нет N = n


Код: Выделить всё
PointerToFormInstance = InterfaceFromHWND(hwnd) ' функция возвращает объект с уже вызванным дополнительным AddRef  N = n+1
For i = 1 to 1000
     Dim PointerToFormInstance2 As Long
     PointerToFormInstance2 = PointerToFormInstance: AddRef(PointerToFormInstance2) ' для Release после CastPtrToIUnknown  N = n+2
     CastPtrToIUnknown(PointerToFormInstance2).Caption = "Привет!" ' N = n+2-1 = n+1
Next i
Release(PointerToFormInstance) ' просто обязаны это сделать N = n+1-1 = n

Итак, где же здесь "комплементарные вызовы AddRef/Release", которые можно убрать?

Хакер писал(а):Уверяю тебя, что если бы ты не нарушил соглашений, ничего бы не падало. Моя функция здесь не причём.

Именно твоя функция и является нестандартной, требуя описаний и комментариев: "Перед вызовом функции убедитесь, что являетесь владельцем объекта, а после функции обнулите переменную и т.п."

Хакер писал(а):Ещё раз, отвлечённо:
VB-шное CastPtrToIUnknown(...) эквивалентном сипипишному (IUnknown*)(...)
Ты действительно считаешь, что статическое кастование должно повлечь вызов AddRef? Считаешь?

Оно не эквивалентно сипипишному ниразу. Аналог сипипишному касту является как раз ObjPtr, который не затрагивает счетчик ссылок.

Во-первых, я могу кастировать несколько раз IUnknown* p1 = (IUnknown*) pObj; IUnknown* p2 = (IUnknown*) pObj; без последствий, поскольку С++, в отличие от VB, не вмешивается в подсчет ссылок (но я бы программисту да и себе по рукам надавал бы за вышеприведенный код).

Во-вторых, кастирование не передает собственность на объект, т.е. объект нельзя удалить ни через p1, ни через p2, потому что поведение С++-объекта, стоящего за pObj, может быть достаточно сложным и недоступным. Чтобы было понятно для тебя, CastPtrToIUnknown забирает указатель на объект в свою собственность и начинает следить за его счетчиком ссылок, лишая этого значение и саму переменную, передаваемую в CastPtrToIUnknown. Т.е. нельзя Release-ить объект через использованный PointerToFormInstance.

PS
Кстати, если правда про GetMemObj, то это вариант эффективней всего ,что было тут предложено, т.к. не вызывает обращений по интерфейсу и по сети.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! (с) КВН

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

Re: Object из указателя

Сообщение jangle » 23.03.2009 (Пн) 23:04

vi - отлично ведешь дисскусию, я просто в восхищении! :)

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

Re: Object из указателя

Сообщение Хакер » 24.03.2009 (Вт) 3:27

Оно не эквивалентно сипипишному ниразу. Аналог сипипишному касту является как раз ObjPtr, который не затрагивает счетчик ссылок.

Является. Сама функция, является. CastPtrToInknown как и ObjPtr не затрагивает счётчик (потому что реализация функций одна и та же).

Выражение, в целом, вероятно не является. Т.е. тебя смущает то, что при использовании CastPtrToIUnknown счётчик ссылок уменьшается, а при использовании сипипишного кастования нет. Действительно уменьшается, но не моей функцией, а по инициативе VB.

С другой стороны, я признаю, что с напутал насчёт того, что мы (вызывающая сторона), а не функция (вызываемая) ответственны за AddRef-инга ByVal-параметра. Но это отдельный разговор: я был в начале марта введён в заблуждение поведением VB, которое навело меня на (ошибочную, получается?) мысль, что всё-таки за вышеописанное действие ответственнен вызыватель.
—We separate their smiling faces from the rest of their body, Captain.
—That's right! We decapitate them.

Vi
Постоялец
Постоялец
 
Сообщения: 739
Зарегистрирован: 25.01.2002 (Пт) 11:03
Откуда: Россия, Ижевск

Re: Object из указателя

Сообщение Vi » 24.03.2009 (Вт) 10:30

Хакер писал(а):Является. Сама функция, является. CastPtrToInknown как и ObjPtr не затрагивает счётчик (потому что реализация функций одна и та же).
Выражение, в целом, вероятно не является. Т.е. тебя смущает то, что при использовании CastPtrToIUnknown счётчик ссылок уменьшается, а при использовании сипипишного кастования нет. Действительно уменьшается, но не моей функцией, а по инициативе VB.

Сравни
Private Declare Function CastPtrToIUnknown Lib "msvbvm60.dll" Alias "VarPtr" (ByVal pUnk As Long) As IUnknown
Это было бы описано в TLB так:
[entry(0x60000006), hidden] IUnknown* CastPtrToIUnknown([in] long pUnk);

и реальное описание
Function VarPtr(Ptr As Any) As Long
и
[entry(0x60000006), hidden] long VarPtr([in] void* Ptr);

Что произошло? А произошли замена входного параметра, что является некритичным, и подмена возвращаемого значения: вместо целого числа функция стала возвращать указатель на объект, который должен быть с увеличенной ссылкой. Следовательно, именно замена описания функции привела к нарушению соглашений СОМ.

Но именно это и делает эту функцию полезной в VB, т.к. VB не дает способа уменьшить (освободить) ссылку для не-объектной переменной.

Хакер писал(а):С другой стороны, я признаю, что с напутал насчёт того, что мы (вызывающая сторона), а не функция (вызываемая) ответственны за AddRef-инга ByVal-параметра. Но это отдельный разговор: я был в начале марта введён в заблуждение поведением VB, которое навело меня на (ошибочную, получается?) мысль, что всё-таки за вышеописанное действие ответственнен вызыватель.

Да я тоже хорош - развел флейм да провокации. Вот такой вариант будет приемлем?
Код: Выделить всё
Private Declare Function CastPtrToIUnknown Lib "msvbvm60.dll" Alias "VarPtr" (ByVal pUnk As Long) As IUnknown
...
Function ObjectFromPTR(ByRef ptr As Long) As Object
  Set ObjectFromPTR = CastPtrToIUnknown(ptr)
  ptr = 0
End Function

И использование
Код: Выделить всё
Private Sub Form_Load()
  Dim PointerToFormInstance As Long, Instanse As Object, i As Long
  ' PointerToFormInstance должен содержать реальную ссылку, полученную извне, например, из параметров lParam и wParam сообщения
  ' Мы же можем получить ее искуственно из Me (пусть и топорно)
       Set Instanse = Me
       PointerToFormInstance = ObjPtr(Instanse) ' получить ссылку
       CopyMemory Instanse, i, 4 ' обнуление Instanse без вызова Release
  ' Получили в PointerToFormInstance увеличенную ссылку на объект Me

  Set Instanse = ObjectFromPTR(PointerToFormInstance)
  For i = 1 To 1000
    Instanse.Caption = "Привет" & i & "!"
  Next
End Sub
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! (с) КВН

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

Re: Object из указателя

Сообщение Хакер » 24.03.2009 (Вт) 10:40

Вот такой вариант будет приемлем?

Не понял смысла функции-обертки. Да и, ещё один момент: объект может не поддерживать IDispatch. Так что лучше всё-таки IUnknown использовать там.

Уж если VB встретится disp-вызов, он сам ведь запросит IDispatch для такого вызова.

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

След.

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

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

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

    TopList