Что нового

Реализация предпросмотра изображений в ListView

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Пытаюсь реализовать предпросмотр изображений в ListView, интересует в первую очередь отображение миниатюр изображений.
А также нужно их расположить также как это делает проводник Windows.

Вот что получилось:

Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GUIListView.au3>
#include <GUIImageList.au3>
#include <GDIPlus.au3>
#include <File.au3>

Global Const $iGUI_W = 800
Global Const $iGUI_H = 600

Global $sImages_Path = @ScriptDir & '\Images'
Global $hImageList = _GUIImageList_Create(64, 64, 5)

_GDIPlus_Startup()

$hGUI = GUICreate('Image Browser', $iGUI_W, $iGUI_H)

$iLV = GUICtrlCreateListView('Name|Creation date|Modified date|Picture taken date|Geolocation', 20, 50, $iGUI_W - 40, $iGUI_H - 70, BitOR($GUI_SS_DEFAULT_LISTVIEW, $LVS_NOCOLUMNHEADER))

_GUICtrlListView_SetView($iLV, 3)
_GUICtrlListView_SetImageList($iLV, $hImageList, 1)

_Load_Images()

GUISetState(@SW_SHOW, $hGUI)

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd

Func _Load_Images()
	Local $aImages = _FileListToArrayRec($sImages_Path, '*.jpg', 1, 1, 0, 2)
	Local $sFName, $hImage, $hThumb, $hBitmap, $iImage
	
	For $i = 1 To UBound($aImages) - 1
		$sFName = StringRegExpReplace($aImages[$i], '^.*\\', '')
		$hImage = _GDIPlus_ImageLoadFromFile($aImages[$i])
		$hThumb = _GDIPlus_ImageGetThumbnail($hImage)
		$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hThumb)
		
		$iImage = _GUIImageList_Add($hImageList, $hBitmap)
		_GUICtrlListView_AddItem($iLV, $sFName, $iImage)
		
		_GDIPlus_ImageDispose($hImage)
		_GDIPlus_ImageDispose($hThumb)
		_WinAPI_DeleteObject($hBitmap)
	Next
EndFunc


Но тут проблема, миниатюры получаются обрезанные, а мне нужно полностью отобразить изображение в миниатюре.

P.S
Код под 3.3.14.2.
 

joiner

Модератор
Локальный модератор
Сообщения
3,557
Репутация
628
Код:
$hThumb = _GDIPlus_ImageGetThumbnail($hImage,64,64)

уменьшение картинок
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486

joiner

Модератор
Локальный модератор
Сообщения
3,557
Репутация
628
а что значит не для всех?
использовал изображения 2592х1944 и меньше.


Добавлено:
Сообщение автоматически объединено:

если установить так
Код:
$hThumb = _GDIPlus_ImageGetThumbnail($hImage,64,64,False)

то все добавляются. вроде -1 не вернула функция. но картинки вытянуты.
не добавляются картинки, которые имеют другую пропорцию - 1944х2592. возможно были перевернуты


Добавлено:
Сообщение автоматически объединено:

фотки, которые были сделаны перевернутой камерой, на телефоне, не добавились. они имеют размер - ширина меньше высоты.
все, которые - ширина больше высоты - добавляются
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Функция ImageGetThumbnail() возвращает эскиз, который был зашит в самом файле при его сохранении (JPG, TIF и т.д.). Если эскиз отсутствует в оригинале, то функция сама создает эскиз, используя заданные параметры.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
joiner [?]
фотки, которые были сделаны перевернутой камерой, на телефоне, не добавились. они имеют размер - ширина меньше высоты.все, которые - ширина больше высоты - добавляются

Yashied [?]
Функция ImageGetThumbnail() возвращает эскиз, который был зашит в самом файле при его сохранении (JPG, TIF и т.д.). Если эскиз отсутствует в оригинале, то функция сама создает эскиз, используя заданные параметры.

Ок, зная это, как теперь сделать всё таки чтобы эскиз брался верно для всех изображений?
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
InnI [?]
Расширенная версия ответа #4 включает рекомендации с примером: Ответ #2
Спасибо, то что нужно.

Остался вопрос с отображением.
Нужно поместить названия у пунктов под сам эскиз.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
У кого то есть идеи как ускорить теперь весь этот процесс?

Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GUIComboBox.au3>
#include <GUIListView.au3>
#include <GUIImageList.au3>
#include <GDIPlus.au3>
#include <File.au3>

_GDIPlus_Startup()

Global Const $iThumb_W = 128
Global Const $iThumb_H = 128
Global Const $iGUI_W = @DesktopWidth - 100
Global Const $iGUI_H = @DesktopHeight - 200

Global Const $sImages_Path = @ScriptDir & '\Images'
Global Const $sNoImage_File = @ScriptDir & '\NoImage.bmp'

Global $hImageList = _GUIImageList_Create($iThumb_W, $iThumb_H, 5)

$hGUI = GUICreate('Image Browser', $iGUI_W, $iGUI_H)

$iLV = GUICtrlCreateListView('File Name|Date|Geolocation', 20, 50, $iGUI_W - 40, $iGUI_H - 70)
GUICtrlSetStyle($iLV, $LVS_ICON)

_GUIImageList_AddBitmap($hImageList, $sNoImage_File)
_GUICtrlListView_SetImageList($iLV, $hImageList, 0)

GUISetState(@SW_SHOW, $hGUI)
_Load_Images()

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd

Func _Load_Images()
	Local $hImage, $hBitmap, $hThumb, $iImage
	Local $aFiles = _FileListToArrayRec($sImages_Path, '*.jpg;*.jpeg;*.bmp;*.png', 1, 1, 0)
	
	If @error Then
		Return
	EndIf
	
	For $i = 1 To $aFiles[0]
		$hImage = _GDIPlus_ImageLoadFromFile($sImages_Path & '\' & $aFiles[$i])
		$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
		
		_GDIPlus_ImageDispose($hImage)
		$hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBitmap)
		
		$hThumb = _GDIPlus_ImageGetThumbnail($hImage, $iThumb_W, $iThumb_H, False)
		$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hThumb)
		$iImage = _GUIImageList_Add($hImageList, $hBitmap)
		
		If $iImage = -1 Then
			_WinAPI_DeleteObject($hBitmap)
			
			$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
			$iImage = _GUIImageList_Add($hImageList, $hBitmap)
		EndIf
		
		$iItem = _GUICtrlListView_AddItem($iLV, StringRegExpReplace($aFiles[$i], '^.*\\', ''), $iImage)
		
		_GDIPlus_ImageDispose($hImage)
		_GDIPlus_ImageDispose($hThumb)
		_WinAPI_DeleteObject($hBitmap)
	Next
EndFunc

Func _GDIPlus_ImageGetThumbnail($hImage, $iWidth = 0, $iHeight = 0, $bKeepRatio = True, $hCallback = Null, $hCallbackData = Null)
	Local $hGDIIPDLL = Eval('ghGDIPDll')
	
	If StringCompare(@AutoItVersion, '3.3.10.2') > 0 Then
		$hGDIIPDLL = Eval('__g_hGDIPDll')
	EndIf
	
	If $bKeepRatio Then
		Local $aImgDim[2] = [_GDIPlus_ImageGetWidth($hImage), _GDIPlus_ImageGetHeight($hImage)]
		If @error Then Return SetError(@error + 20, @extended, False)

		Local $f
		
		If $iWidth < 1 Or $iHeight < 1 Then
			$iWidth = 0
			$iHeight = 0
		Else
			If ($aImgDim[0] / $aImgDim[1]) > 1 Then
				$f = $aImgDim[0] / $iWidth
			Else
				$f = $aImgDim[1] / $iHeight
			EndIf
			$iWidth = Int($aImgDim[0] / $f)
			$iHeight = Int($aImgDim[1] / $f)
		EndIf
	EndIf

	Local $aResult = DllCall($hGDIIPDLL, "int", "GdipGetImageThumbnail", "handle", $hImage, "uint", $iWidth, "uint", $iHeight, "ptr*", 0, "ptr", $hCallback, "ptr", $hCallbackData)
	If @error Then Return SetError(@error, @extended, False)
	If $aResult[0] Then Return SetError(10, $aResult[0], False)

	Return $aResult[4]
EndFunc


Когда в папке загрузки много файлов, грузится очень долго.
 

asdf8

Скриптер
Сообщения
564
Репутация
152
CreatoR [?]
Когда в папке загрузки много файлов, грузится очень долго.
Эта проблема у всех просмотрщиков изображений. Решается, обычно, кэшированием превьюшек.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
asdf8 [?]
Решается, обычно, кэшированием превьюшек.
Я вот что подумал, грузить превьюшки по мере отображения...

Соответственно вопрос - как узнать какие элементы ListView находятся в поле зрения? :scratch:
 

asdf8

Скриптер
Сообщения
564
Репутация
152
CreatoR [?]
как узнать какие элементы ListView находятся в поле зрения?
Код:
_GUICtrlListView_GetItemPosition



грузить превьюшки по мере отображения
Не проще через AdlibRegister или таймер с обратным вызовом? Если скролить колесом мыши скорость скрола не большая.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
asdf8 [?]
Если скролить колесом мыши скорость скрола не большая
Но сам проводник кажется именно так и делает, там со скроллом всё ок.
 

asdf8

Скриптер
Сообщения
564
Репутация
152
CreatoR [?]
Но сам проводник кажется именно так и делает
Не знаю как на семерке, а на ХР - точно не так. Хорошо заметно на папках с очень большим количеством изображений.
 

Naisho

Знающий
Сообщения
86
Репутация
12
CreatoR сказал(а):
Соответственно вопрос - как узнать какие элементы ListView находятся в поле зрения? :scratch:


Можно воспользоваться виртуальным ListView - там как раз это и сделано
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Naisho [?]
Можно воспользоваться виртуальным ListView - там как раз это и сделано
Это хорошо, но как мне задавать с ним группы?
Пишут что виртуальный ListView не поддерживает группы, но это просто не документировано, вот тут написано то это возможно, но как это дело в аутоит перевести? :scratch:
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
CreatoR [?]
вот тут написано то это возможно, но как это дело в AutoIt перевести?
Должно получится, если там все правильно написано.
Код:
SendMessage(hWndLvw, LVM_QUERYINTERFACE, reinterpret_cast<WPARAM>(&IID_IListView), 
            reinterpret_cast<LPARAM>(&pListView));
Так получаем указатель на интерфейс IListView, зная указатель через
Код:
ObjCreateInterface
создаете интерфейс, описание его есть в статье.
В созданном объекте вызываете метод SetOwnerDataCallback(...); и передаете указатель на объект реализующий интерфейс IOwnerDataCallback. У нас на форуме или на официальном, есть примеры как создавать такие объекты. Вот, например, я делал callback в этой теме. Смотрите функцию ObjectFromTag
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
inververs [?]
Должно получится, если там все правильно написано
Я с этими объектами не так сильно дружу, если сможете написать решение вот для такого пример (виртуальный ListView), то буду признателен.

Код:
#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <GUIListView.au3>

$hGui = GUICreate('Virtual ListView search', 300, 230)

Local $idLV = GUICtrlCreateListView('', 10, 40, 300 - 20, 200 - 20, $LVS_OWNERDATA, BitOR($WS_EX_CLIENTEDGE, $LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT))
$hLV = GUICtrlGetHandle($idLV)
_GUICtrlListView_AddColumn($hLV, 'Items', 250)
_GUICtrlListView_EnableGroupView($hLV)

GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')

GUISetState(@SW_SHOW)

Dim $aItems[10]

For $i = 0 To 9
	$aItems[$i] = 'Item' & $i + 1
Next

; Display items
GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, UBound($aItems), 0)

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			ExitLoop
	EndSwitch
WEnd


Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
	Local Static $tText = DllStructCreate('wchar[50]')
	Local Static $pText = DllStructGetPtr($tText)
	
	Local $tNMHDR, $hWndFrom, $iCode
	$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
	$hWndFrom = HWnd(DllStructGetData($tNMHDR, 'hWndFrom'))
	$iCode = DllStructGetData($tNMHDR, 'Code')
	
	Switch $hWndFrom
		Case $hLV
			Switch $iCode
				Case $LVN_GETDISPINFOW
					Local $tNMLVDISPINFO = DllStructCreate($tagNMLVDISPINFO, $lParam)
					
					If BitAND(DllStructGetData($tNMLVDISPINFO, 'Mask'), $LVIF_TEXT) Then
						Local $sItem = $aItems[DllStructGetData($tNMLVDISPINFO, 'Item')]
						
						DllStructSetData($tText, 1, $sItem)
						DllStructSetData($tNMLVDISPINFO, 'Text', $pText)
						DllStructSetData($tNMLVDISPINFO, 'TextMax', StringLen($sItem))
						
						;Странно, но в структуре есть упоминание о группе, почему не реагирует?
						DllStructSetData($tNMLVDISPINFO, 'GroupID', 0)
					EndIf
			EndSwitch
	EndSwitch
	
	Return $GUI_RUNDEFMSG
EndFunc
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
А я не очень понимаю в ListView. Где вы заполняете группы? И что это такое?

CreatoR [?]
если сможете написать решение вот для такого пример (виртуальный ListView)
Это все не надежно будет, они не документированы, и IID может меняться, так в статье IID_IListView = {0x2FFE2979, 0x5928, 0x4386, 0:rofl:B, 0x8E, 0x1F, 0x15, 0xB7, 0x2F, 0xB4}}, а у меня в реестре он определен как: HKEY_CLASSES_ROOT\Interface\{BDD1F049-858B-11D1-B16A-00C0F0283628}, уже не совпадает.
Как вариант, искать каждый раз в реестре и кэшировать. У меня пока нету времени, может позже сделаю, но лучше вам найти другой способ. :scratch:


Добавлено:
Сообщение автоматически объединено:

Не получается методом из статьи у меня, вот этот момент:
Код:
SendMessage(hWndLvw, LVM_QUERYINTERFACE, reinterpret_cast<WPARAM>(&IID_IListView), 
            reinterpret_cast<LPARAM>(&pListView));
Ничего не возвращает в pListView. Хз почему, может руки кривые, но я по всякому пробовал. :whistle:

По второму способу
Alternatively, send message 0x10BB to the List-View control, with wParam addressing the IOwnerDataCallback interface.
удается подключить событие, но перестает работать WM_NOTIFY, и не ясно как показывать записи.

Вот такие вот коврижки. Можно поспрашивать LarsJ, он делал всякие веселые штуки для list view, раз, два

Код:
#include <GuiListView.au3>
#include <GUIConstants.au3>

Global Const $sIID_IOwnerDataCallback = '{44C09D56-8D3B-419D-A462-7B956B105B47}'
Global Const $dtag_IOwnerDataCallback = _
		"GetItemPosition hresult(int;ptr*);" & _ ; int itemIndex, LPPOINT pPosition
		"SetItemPosition hresult(int;ptr);" & _ ; int itemIndex POINT position
		"GetItemInGroup hresult(int;int;ptr*);" & _ ;int groupIndex int groupWideItemIndex PINT pTotalItemIndex
		"GetItemGroup hresult(int;int;ptr*;);" & _ ;int itemIndex,int occurenceIndex, PINT pGroupIndex
		"GetItemGroupCount hresult(int;ptr*);" & _ ;
		"OnCacheHint hresult(int;int);" ;LVITEMINDEX firstItem ;LVITEMINDEX lastItem


Global Const $sIID_IOleWindow = '{00000114-0000-0000-C000-000000000046}'
Global Const $dtag_IOleWindow = _
		"GetWindow hresult(hwnd*);" & _      ; Gets a window handle.
		"ContextSensitiveHelp hresult(int);" ; Controls enabling of context-sensitive help.
Global Const $sIID_IListView = '{BDD1F049-858B-11D1-B16A-00C0F0283628}'
;~ Global Const $sIID_IListView = '{F4D83600-895E-11D0-B0A6-000000000000}'
Global Const $dtag_IListView = $dtag_IOleWindow & _
		"GetImageList hresult();" ; ИТД, пока нету всех методов, т.к не работает

;~ {BDD1F049-858B-11D1-B16A-00C0F0283628}
;~ {F4D83600-895E-11D0-B0A6-000000000000}
Global Const $LVM_QUERYINTERFACE = $LVM_FIRST + 189



GUICreate("ListView Insert Group", 400, 300)
Global $idListview = GUICtrlCreateListView('', 10, 40, 300 - 20, 200 - 20, $LVS_OWNERDATA, BitOR($WS_EX_CLIENTEDGE, $LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT))
Global $hLV = GUICtrlGetHandle($idListview)

_GUICtrlListView_AddColumn($hLV, 'Items', 250)

GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
GUISetState(@SW_SHOW)

;==========================
#1 Вариант http://www.geoffchappell.com/studies/windows/shell/comctl32/controls/listview/messages/queryinterface.htm
;~ Local Const $tRIID_IListView = _WinAPI_GUIDFromString($sIID_IListView)
;~ Local $pListView
;~ Local $aResult = _SendMessage ($hLV, $LVM_QUERYINTERFACE, $tRIID_IListView, 0, 5, 'struct*')
;~ If Not IsArray($aResult) Or Not $aResult[4] Then
;~ 	MsgBox(0, 'Ошибка', 'LVM_QUERYINTERFACE не возвратил указатель')
;~ 	Exit @ScriptLineNumber
;~ EndIf
;==========================
;==========================
#2 Вариант http://www.geoffchappell.com/studies/windows/shell/comctl32/controls/listview/interfaces/iownerdatacallback.htm?tx=25
Local $tEvent
Local $oEvent = __ObjectCreate("__vl_" & 'IOwnerDataCallback' & "_", $dtag_IOwnerDataCallback, $tEvent, False)
_SendMessage($hLV, 0x10BB, $oEvent())
;==========================


Local $iGroupID = 1
_GUICtrlListView_InsertGroup($idListview, -1, $iGroupID, "Group 1")
_GUICtrlListView_EnableGroupView($hLV)
Global $iItems = 1
GUICtrlSendMsg($idListview, $LVM_SETITEMCOUNT, $iItems, 0)
Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE
Exit

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
	Local Static $tText = DllStructCreate('wchar[50]')
	Local Static $pText = DllStructGetPtr($tText)

	Local $tNMHDR, $hWndFrom, $iCode
	$tNMHDR = DllStructCreate($tagNMHDR, $lParam)
	$hWndFrom = HWnd(DllStructGetData($tNMHDR, 'hWndFrom'))
	$iCode = DllStructGetData($tNMHDR, 'Code')

	Switch $hWndFrom
		Case $hLV
			Switch $iCode
				Case $LVN_GETDISPINFOW
					ConsoleWrite('$LVN_GETDISPINFOW' & @CRLF)
;~                     Local $tNMLVDISPINFO = DllStructCreate($tagNMLVDISPINFO, $lParam)
;~
;~                     If BitAND(DllStructGetData($tNMLVDISPINFO, 'Mask'), $LVIF_TEXT) Then
;~                         Local $sItem = $aItems[DllStructGetData($tNMLVDISPINFO, 'Item')]
;~
;~                         DllStructSetData($tText, 1, $sItem)
;~                         DllStructSetData($tNMLVDISPINFO, 'Text', $pText)
;~                         DllStructSetData($tNMLVDISPINFO, 'TextMax', StringLen($sItem))
;~
;~                         ;Странно, но в структуре есть упоминание о группе, почему не реагирует?
;~                         DllStructSetData($tNMLVDISPINFO, 'GroupID', 0)
;~                     EndIf
			EndSwitch
	EndSwitch

	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func __ObjectCreate($sFunctionPrefix, $tagInterface, ByRef $tInterface, $fPrint = False, $bIsUnknown = Default, $sIID = "{00000000-0000-0000-C000-000000000046}") ; last param is IID_IUnknown by default
	If $bIsUnknown = Default Then $bIsUnknown = True
	Local $sInterface = $tagInterface ; copy interface description
	Local $tagIUnknown = "QueryInterface hresult(ptr;ptr*);" & _
			"AddRef dword();" & _
			"Release dword();"
	; Adding IUnknown methods
	If $bIsUnknown Then $tagInterface = $tagIUnknown & $tagInterface
	; Below line is really simple even though it looks super complex. It's just written weird to fit in one line, not to steal your attention
	Local $aMethods = StringSplit(StringReplace(StringReplace(StringReplace(StringReplace(StringTrimRight(StringReplace(StringRegExpReplace(StringRegExpReplace($tagInterface, "\w+\*", "ptr"), "\h*(\w+)\h*(\w+\*?)\h*(\((.*?)\))\h*(;|;*\z)", "$1\|$2;$4" & @LF), ";" & @LF, @LF), 1), "object", "idispatch"), "hresult", "long"), "bstr", "ptr"), "variant", "ptr"), @LF, 3)
	Local $iUbound = UBound($aMethods)
	Local $sMethod, $aSplit, $sNamePart, $aTagPart, $sTagPart, $sRet, $sParams, $hCallback
	; Allocation
	$tInterface = DllStructCreate("int RefCount;int Size;ptr Object;ptr Methods[" & $iUbound & "];int_ptr Callbacks[" & $iUbound & "];ulong_ptr Slots[16]") ; 16 pointer sized elements more to create space for possible private props
	If @error Then Return SetError(1, 0, 0)
	For $i = 0 To $iUbound - 1
		$aSplit = StringSplit($aMethods[$i], "|", 2)
		If UBound($aSplit) <> 2 Then ReDim $aSplit[2]
		$sNamePart = $aSplit[0]
		$sTagPart = $aSplit[1]
		$sMethod = $sFunctionPrefix & $sNamePart
		If $fPrint Then
			Local $iPar = StringInStr($sTagPart, ";", 2), $t
			If $iPar Then
				$t = "Ret: " & StringLeft($sTagPart, $iPar - 1) & "  " & _
						"Par: " & StringRight($sTagPart, StringLen($sTagPart) - $iPar)
			Else
				$t = "Ret: " & $sTagPart
			EndIf
			Local $s = "Func " & $sMethod & _
					"($pSelf) ; " & $t & @CRLF & _
					"EndFunc" & @CRLF
			ConsoleWrite($s)
		EndIf
		$aTagPart = StringSplit($sTagPart, ";", 2)
		$sRet = $aTagPart[0]
		$sParams = StringReplace($sTagPart, $sRet, "", 1)
		$sParams = "ptr" & $sParams
		If Not $fPrint Then
			$hCallback = DllCallbackRegister($sMethod, $sRet, $sParams)
			If @error Then
				ConsoleWrite('! ' & @error & ' ' & $sMethod & ' ' & $sParams & @CRLF & @CRLF)
			EndIf
			DllStructSetData($tInterface, "Methods", DllCallbackGetPtr($hCallback), $i + 1) ; save callback pointer
			DllStructSetData($tInterface, "Callbacks", $hCallback, $i + 1) ; save callback handle
		EndIf
	Next
	If Not $fPrint Then
		DllStructSetData($tInterface, "RefCount", 1) ; initial ref count is 1
		DllStructSetData($tInterface, "Size", $iUbound) ; number of interface methods
		DllStructSetData($tInterface, "Object", DllStructGetPtr($tInterface, "Methods")) ; Interface method pointers
		Return ObjCreateInterface(DllStructGetPtr($tInterface, "Object"), $sIID, $sInterface, $bIsUnknown) ; pointer that's wrapped into object
	EndIf
EndFunc   ;==>__ObjectCreate

Func __mbn_DeleteObjectFromTag(ByRef $tInterface)
	For $i = 1 To DllStructGetData($tInterface, "Size")
		DllCallbackFree(DllStructGetData($tInterface, "Callbacks", $i))
	Next
	$tInterface = 0
EndFunc   ;==>__mbn_DeleteObjectFromTag
Func __StringFromGUID($pGUID)
	Local $aResult = DllCall("ole32.dll", "int", "StringFromGUID2", "struct*", $pGUID, "wstr", "", "int", 40)
	If @error Then Return SetError(@error, @extended, "")
	Return SetExtended($aResult[0], $aResult[2])
EndFunc   ;==>__StringFromGUID

Func __vl_IOwnerDataCallback_GetItemGroupCount($pSelf, $iItemIndex, $pOccurenceCount) ; Ret: long  Par: int; ptr
	ConsoleWrite('__vl_IOwnerDataCallback_GetItemGroupCount ' & $iItemIndex & ' ' & $pOccurenceCount & @CRLF)
	DllStructSetData(DllStructCreate("ptr", $pOccurenceCount), 1, 1)
	Return 0 ; $S_OK
EndFunc   ;==>__vl_IOwnerDataCallback_GetItemGroupCount
Func __vl_IOwnerDataCallback_GetItemInGroup($pSelf, $iGroupIndex, $iGroupWideItemIndex, $pTotalItemIndex) ; Ret: long  Par: int;int;ptr
;~ GetItemGroup maps indexes in the opposite direction. It is called with a total item index, and returns this item's group index:
	ConsoleWrite('__vl_IOwnerDataCallback_GetItemInGroup' & $iGroupIndex & ' ' & $iGroupWideItemIndex & ' ' & $pTotalItemIndex & @CRLF)

;~     // we want group 0 to contain items 0, 3, 6...
;~     //         group 1            items 1, 4, 7...
;~     //         group 2            items 2, 5, 8...
;~     *pTotalItemIndex = groupIndex + groupWideItemIndex * 3;

	DllStructSetData(DllStructCreate("ptr", $pTotalItemIndex), 1, $iGroupIndex + $iGroupWideItemIndex * 1)
	Return 0 ; $S_OK
EndFunc   ;==>__vl_IOwnerDataCallback_GetItemInGroup
Func __vl_IOwnerDataCallback_GetItemGroup($pSelf, $iItemIndex, $iOccurenceIndex, $pGroupIndex) ; Ret: long  Par: int;int;int
	ConsoleWrite('__vl_IOwnerDataCallback_GetItemGroup ' & $iItemIndex & ' ' & $iOccurenceIndex & ' ' & $pGroupIndex & @CRLF)
;~ 	__vl_IOwnerDataCallback_GetItemGroup 0 0 0x00D2F4F4
;~ GetItemGroup maps indexes in the opposite direction. It is called with a total item index, and returns this item's group index:
;~     // group 0 contains items 0, 3, 6...
;~     // group 1 contains items 1, 4, 7...
;~     // group 2 contains items 2, 5, 8...
;~     *pGroupIndex = itemIndex % 3;
;~     return S_OK;
;~ That's it. The occurenceIndex parameter is useful only if you want single items to appear in multiple groups.

	DllStructSetData(DllStructCreate("ptr", $pGroupIndex), 1, 1)
	Return 0 ; $S_OK
EndFunc   ;==>__vl_IOwnerDataCallback_GetItemGroup
Func __vl_IOwnerDataCallback_QueryInterface($pSelf, $pRIID, $pObj) ; Ret: long  Par: ptr;ptr

	Local Static $sIID_IUnknown = "{00000000-0000-0000-C000-000000000046}"
	Local $sIID = __StringFromGUID($pRIID)


	ConsoleWrite('__vl_IOwnerDataCallback_QueryInterface ' & $sIID & @CRLF)
	If $sIID = $sIID_IUnknown Then
		DllStructSetData(DllStructCreate("ptr", $pObj), 1, $pSelf)
		Return 0 ; 0 ; $S_OK
	ElseIf $sIID = $sIID_IOwnerDataCallback Then
		DllStructSetData(DllStructCreate("ptr", $pObj), 1, $pSelf)
		Return 0 ; $S_OK
	Else
		Return 0x80004002 ; $E_NOINTERFACE
	EndIf
EndFunc   ;==>__vl_IOwnerDataCallback_QueryInterface
Func __vl_IOwnerDataCallback_AddRef($pSelf) ; Ret: dword
;~ 	ConsoleWrite('__vl_IOwnerDataCallback_AddRef' & @CRLF)
	Return 1
EndFunc   ;==>__vl_IOwnerDataCallback_AddRef
Func __vl_IOwnerDataCallback_Release($pSelf) ; Ret: dword
	Return 1
EndFunc   ;==>__vl_IOwnerDataCallback_Release
Func __vl_IOwnerDataCallback_GetItemPosition($pSelf, $iItemIndex, $pPosition) ; Ret: long  Par: int; ptr
	ConsoleWrite('__vl_IOwnerDataCallback_GetItemPosition' & @CRLF)
;~ 	Return 0 ; $S_OK
	Return 0x80004002 ; $E_NOINTERFACE
EndFunc   ;==>__vl_IOwnerDataCallback_GetItemPosition
Func __vl_IOwnerDataCallback_SetItemPosition($pSelf, $iItemIndex, $pPosition) ; Ret: long  Par: int; ptr
	ConsoleWrite('__vl_IOwnerDataCallback_SetItemPosition' & @CRLF)
;~ 	Return 0 ; $S_OK
	Return 0x80004002 ; $E_NOINTERFACE
EndFunc   ;==>__vl_IOwnerDataCallback_SetItemPosition
Func __vl_IOwnerDataCallback_OnCacheHint($pSelf, $p1, $p2) ; Ret: long
	Return 0x80004002 ; $E_NOINTERFACE
;~ 	Return 0 ; $S_OK
EndFunc   ;==>__vl_IOwnerDataCallback_OnCacheHint
 
Верх