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
По-поводу создания объекта неправильно выразился, имел ввиду сделать так чтобы object ссылался на имеющийся указатель. А чем код плох и какой есть вариант?
SLIM писал(а):Первый вариант вопроса более вменяем чем второй.
Если первое невозможно, то второе уж точно
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
Хакер писал(а):[*]Автор этого кода по совокупности вышесказанного — дятел. Он кодер, механический кодер, который просто использует подсмотренные где-то приёмы, но ему глубоко фиолетово, как оно работает изнутри1. [/list]
Хакер писал(а):Авторитет у него может и больше, и рассказы у него душевные, но вот этот код его — лажа.
Можно продолжить перечислять недостатки: его код нарушает соглашение COM относительно того, кто ответственнен за AddRef/Release-вызовы.
RayShade писал(а):Да, науке известны многочисленные случаи падения IDE при попытках сделать на VB различные нетривиальные вещи
Vi, по соглашению: функция, которая принимает ссылку на объект и возвращает её же, не должна увеличивать счётчик у этого объекта. Моя не увеличивает. Это просто способ скастовать long к (IUnknown*). Всё остальное: вызов QI для получения нужного интерфейса, вызовы AddRef/Release будет сделано VB автоматически.
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.
То, что что-то падает, совсем не показатель того, что соглашение нарушено.
For i = 1 To 10
CastPtrToIUnknown(PointerToFormInstance).Caption = "Привет" & i & "!"
Next
Vi писал(а):Например, так:
- Код: Выделить всё
For i = 1 To 10
CastPtrToIUnknown(PointerToFormInstance).Caption = "Привет" & i & "!"
Next
Хакер писал(а):Vi, я тебе скажу, откуда берётся крах. Крах берётся оттуда, что вызов ObjPtr происходит с нарушением COM-соглашения.
Хакер писал(а):Это нарушение, заложенное в VB, плюс нарушение, заложенное в код jangle невилируют друг-друга.
Хакер писал(а):CastPtrToIUnknown всего лишь кастует типы. Если бы в VB были кастования как в С/С++, проблемы бы не было вообще. Посколько это кастование, даже логически ясно, что никаких AddRef/Release вызовов быть не должно.
Хакер писал(а):Функция, принимающая в качестве одного из аргументов указатель на интерфейс, внутри себя сама должна вызвать Release, когда этот параметр ей больше не нужен.
Хакер писал(а):На самом деле, я могу предоставить простой пример, показывающий, что мой вариант ничего не нарушает, а вариант jangle — делает лишний AddRef.Хочешь?
Vi писал(а):С другими двумя соглашусь, но вот это неверно. Аргументы функции никогда не могут быть от-Release-ны внутри функции. НИКОГДА. Просто потому, что он, переданный указатель, используется во внешнем коде, про который функция не может и не должна делать никаких предположений.
Т.е. твой пример ошибочен и не должен был появиться в качестве примера. Или был должен явно указать допущения и предположения.
AddRef(PointerToFormInstance): CastPtrToIUnknown(PointerToFormInstance).Caption = "Привет!"
Release(PointerToFormInstance)
For i = 1 to 1000
AddRef(PointerToFormInstance): CastPtrToIUnknown(PointerToFormInstance).Caption = "Привет!"
Next i
Release(PointerToFormInstance)
Не соглашусь. ObjPtr (Function ObjPtr(Ptr As Unknown) As Long) и VarPtr (Function VarPtr(Ptr As Any) As Long) ничего не нарушают, и, тем более, нарушения не заложены в VB. Нарушают те, кто используют эти функции не по своему назначению. Эти функции возвращают адрес, причем они являются недокументированными (или отчасти документированными).
Я бы согласился здесь с тобой, но нужно указывать тот факт, что после использования переменной типа Long в качестве параметра функции CastPtrToIUnknown эта переменная содержит неверные данные и не должна быть использована в дальнейшем.
Т.е. нельзя использовать CastPtrToIUnknown(PointerToFormInstance) с последующим CastPtrToIUnknown(PointerToFormInstance), а нужно перекидывать значение в объектную переменную Set pInstanceObject = CastPtrToIUnknown(PointerToFormInstance) и сразу же PointerToFormInstance = 0, чтобы не было соблазна его использовать.
CastPtrToIUnknown(...)
(IUnknown*)(...)
RayShade писал(а):Я понимаю дискуссию примерно наполовину, но тоже хочу пример
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"
...
Хакер писал(а):VBAccelerator — огромный рассадник быдлокода... тоже мне, нашёл авторитетный источник.
Хакер писал(а):Мой пример ни разу не ошибоычный.Поясню.Я просто убрал пару комплементарных вызовов AddRef/Release. Это допускается, это поощряемая техника оптимизации. И я убрал их в целях оптимизации и упрощения кода.
Я мог бы их не убирать, тогда мой пример выглядел бы так:
- Код: Выделить всё
AddRef(PointerToFormInstance): CastPtrToIUnknown(PointerToFormInstance).Caption = "Привет!"
Release(PointerToFormInstance)
Хакер писал(а):Я тебе напомню, насчёт соглашений:
1) Если мы передаём в функцию указатель на интерфейс, мы (а не функция) должны должны вызвать AddRef, перед тем, как передать.
2) Функция, принимающая в качестве одного из аргументов указатель на интерфейс, внутри себя сама должна вызвать Release, когда этот параметр ей больше не нужен.
3) Функция, если она возвращает указатель на интерфейс, сама внутри себя должна вызвать AddRef у интерфейса, указатель на который она возвращает.
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
Хакер писал(а):Уверяю тебя, что если бы ты не нарушил соглашений, ничего бы не падало. Моя функция здесь не причём.
Хакер писал(а):Ещё раз, отвлечённо:
VB-шное CastPtrToIUnknown(...) эквивалентном сипипишному (IUnknown*)(...)
Ты действительно считаешь, что статическое кастование должно повлечь вызов AddRef? Считаешь?
Оно не эквивалентно сипипишному ниразу. Аналог сипипишному касту является как раз ObjPtr, который не затрагивает счетчик ссылок.
Хакер писал(а):Является. Сама функция, является. CastPtrToInknown как и ObjPtr не затрагивает счётчик (потому что реализация функций одна и та же).
Выражение, в целом, вероятно не является. Т.е. тебя смущает то, что при использовании CastPtrToIUnknown счётчик ссылок уменьшается, а при использовании сипипишного кастования нет. Действительно уменьшается, но не моей функцией, а по инициативе 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
Вот такой вариант будет приемлем?
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 15