Hello,
I am starting with apologies for the long post. Here a little experiment I am doing at home.
It is an harbour/com interface, an I am starting with IPreviewHadler. For now the file are created by hand, but i am writing an harbour program that create them from idl.
let start with IUnknown, the COM base class:
Code: Select all | Expand
#include <hbclass.ch>
FUNCTION ExaVal( cString )
LOCAL nX, nVal
LOCAL cNewString := upper(AllTrim( cString ))
LOCAL nLen := Len( cNewString )
LOCAL nNumber := 0
FOR nX := 1 TO nLen
nVal := At( SubStr( cNewString, nX, 1 ), "0123456789ABCDEF" ) - 1
if nVal<0
return 0
endif
nNumber += ( nVal * ( 16 ** ( nLen - nX ) ) )
NEXT
RETURN nNumber
FUNC iidFromString(str)
LOCAL r
//example: {00000000-0000-0000-0000-000000000000}
// 12345678901234567890123456789012345678
// 1 2 3
if len(str)<>38 .or. ;
substr(str,1,1) <> "{" .or. substr(str,38,1) <> "}" .or. ;
substr(str,10,1) <> "-" .or. substr(str,15,1) <> "-" .or. ;
substr(str,20,1) <> "-" .or. substr(str,25,1) <> "-"
return {}
endif
r := Array(11)
r[1] := ExaVal(substr(str,2,8))
r[2] := ExaVal(substr(str,11,4))
r[3] := ExaVal(substr(str,16,4))
r[4] := ExaVal(substr(str,21,2))
r[5] := ExaVal(substr(str,23,2))
r[6] := ExaVal(substr(str,26,2))
r[7] := ExaVal(substr(str,28,2))
r[8] := ExaVal(substr(str,30,2))
r[9] := ExaVal(substr(str,32,2))
r[10] := ExaVal(substr(str,34,2))
r[11] := ExaVal(substr(str,36,2))
return r
CLASS IUnknown
DATA iPtr
METHOD New(iptr) CONSTRUCTOR
METHOD AddRef()
Destructor Release()
METHOD QueryInterface(riid, dest)
METHOD SetPtr(ptr)
endclass
METHOD New(iptr) CLASS IUnknown
::iPtr := iptr
return Self
METHOD SetPtr(ptr) CLASS IUnknown
if Valtype(::iPtr) == "P"
::Release()
endif
::iPtr := ptr
if Valtype(::iPtr) == "P"
::AddRef()
endif
return nil
#pragma BEGINDUMP
#include <windows.h>
#include <hbapi.h>
#include <hbstack.h>
#include <hbapiitm.h>
#include <stdio.h>
/* 0*/ typedef HRESULT (__stdcall *IUnknown_QueryInterface )(void* This,REFIID riid,void **ppvObject);
/* 1*/ typedef ULONG (__stdcall *IUnknown_AddRef )(void* This);
/* 2*/ typedef ULONG (__stdcall *IUnknown_Release )(void* This);
void* GetFunctionPtr(void* ptrInt,int id)
{
void** _i = (void**)(*(void**)ptrInt);
return _i+id;
}
GUID GUIDFromArray(PHB_ITEM pArr)
{
GUID ret;
ret.Data1 = (unsigned long)(hb_itemGetND(hb_itemArrayGet(pArr,1)));
ret.Data2 = (unsigned short)hb_itemGetNL(hb_itemArrayGet(pArr,2));
ret.Data3 = (unsigned short)hb_itemGetNL(hb_itemArrayGet(pArr,3));
ret.Data4[0] = (unsigned char)hb_itemGetNL(hb_itemArrayGet(pArr,4));
ret.Data4[1] = (unsigned char)hb_itemGetNL(hb_itemArrayGet(pArr,5));
ret.Data4[2] = (unsigned char)hb_itemGetNL(hb_itemArrayGet(pArr,6));
ret.Data4[3] = (unsigned char)hb_itemGetNL(hb_itemArrayGet(pArr,7));
ret.Data4[4] = (unsigned char)hb_itemGetNL(hb_itemArrayGet(pArr,8));
ret.Data4[5] = (unsigned char)hb_itemGetNL(hb_itemArrayGet(pArr,9));
ret.Data4[6] = (unsigned char)hb_itemGetNL(hb_itemArrayGet(pArr,10));
ret.Data4[7] = (unsigned char)hb_itemGetNL(hb_itemArrayGet(pArr,11));
return ret;
}
HB_FUNC( COCREATEINSTANCE ) //clsid, ctx, riid, dest
{
GUID clsid = GUIDFromArray(hb_param(1, HB_IT_ARRAY ));
DWORD ctx = hb_parnl( 2 );
GUID riiid = GUIDFromArray(hb_param(3, HB_IT_ARRAY ));
void* ptr;
//wchar_t test[50];
//StringFromGUID2(&clsid,test,50);
//MessageBoxW(0,test,L"CLSID",MB_OK);
//StringFromGUID2(&riiid,test,50);
//MessageBoxW(0,test,L"RIIID",MB_OK);
HRESULT hr;
#if defined(__cplusplus)
hr = CoCreateInstance( clsid, 0, ctx, riiid, ( void ** ) &ptr );
#else
hr = CoCreateInstance( &clsid, 0, ctx, &riiid, ( void ** ) &ptr );
#endif
if(ptr)
hb_storptr(ptr, 4);
else
hb_stor(4);
hb_retnl(hr);
}
HB_FUNC( IUNKNOWN_QUERYINTERFACE )
{
PHB_ITEM pSelf = hb_stackSelfItem();
void* ptr = hb_itemGetPtr(hb_itemArrayGet(pSelf,1));
if(ptr)
{
IUnknown_QueryInterface* fn = (IUnknown_QueryInterface*)GetFunctionPtr(ptr,0);
GUID riiid = GUIDFromArray(hb_param(1, HB_IT_ARRAY ));
void* pvObject;
HRESULT ret = (*fn)(ptr,&riiid,&pvObject);
if( pvObject != 0 )
hb_storptr(pvObject,2);
else
hb_stor(2);
hb_retnl(ret);
} else
{
hb_stor(2); //nil
hb_retnl(0x8032001C); //A required pointer is null.
}
}
HB_FUNC( IUNKNOWN_ADDREF )
{
PHB_ITEM pSelf = hb_stackSelfItem();
void* ptr = hb_itemGetPtr(hb_itemArrayGet(pSelf,1));
ULONG ret;
if( ptr )
{
IUnknown_AddRef* fn = (IUnknown_AddRef*)GetFunctionPtr(ptr,1);
ret = (*fn)(ptr);
} else
{
ret = 0x8032001C; //A required pointer is null.
}
hb_retnl(ret);
}
HB_FUNC( IUNKNOWN_RELEASE )
{
PHB_ITEM pSelf = hb_stackSelfItem();
void* ptr = hb_itemGetPtr(hb_itemArrayGet(pSelf,1));
ULONG ret;
if( ptr )
{
IUnknown_Release* fn = (IUnknown_Release*)GetFunctionPtr(ptr,2);
ret = (*fn)(ptr);
} else
{
ret = 0x8032001C; //A required pointer is null.
}
hb_retnl(ret);
}
#pragma ENDDUMP
now the intefaces we needs for preview: IPreviewHandler
Code: Select all | Expand
#include <hbclass.ch>
/* From ShObjIdl.idl
[
object,
uuid(8895b1c6-b41f-4c1c-a562-0d564250836f),
]
interface IPreviewHandler : IUnknown
{
HRESULT SetWindow(
[in] HWND hwnd,
[in] const RECT *prc);
HRESULT SetRect([in] const RECT *prc);
HRESULT DoPreview();
HRESULT Unload();
HRESULT SetFocus();
HRESULT QueryFocus([out] HWND* phwnd);
HRESULT TranslateAccelerator([in] MSG* pmsg);
}
*/
#define IID_IPreviewHandler {0x8895b1c6,0xb41f,0x4c1c,0xa5,0x62,0x0d,0x56,0x42,0x50,0x83,0x6f}
class IPreviewHandler FROM IUnknown
METHOD SetWindow(hwnd,prc)
METHOD SetRect(prc)
METHOD DoPreview()
METHOD Unload()
METHOD SetFocus()
METHOD QueryFocus(phwnd)
//METHOD TranslateAccelerator(pmsg); msg strunct non handled
endclass
#pragma BEGINDUMP
#include <windows.h>
#include <hbapi.h>
#include <hbstack.h>
#include <hbapiitm.h>
/* 3*/typedef HRESULT (__stdcall *IPreviewHandler_SetWindow)(void* This,HWND hwnd,const RECT *prc);
/* 4*/typedef HRESULT (__stdcall *IPreviewHandler_SetRect)(void* This,const RECT *prc);
/* 5*/typedef HRESULT (__stdcall *IPreviewHandler_DoPreview)(void* This);
/* 6*/typedef HRESULT (__stdcall *IPreviewHandler_Unload)(void* This);
/* 7*/typedef HRESULT (__stdcall *IPreviewHandler_SetFocus)(void* This);
/* 8*/typedef HRESULT (__stdcall *IPreviewHandler_QueryFocus)(void* This,HWND* phwnd);
/* 9*/typedef HRESULT (__stdcall *IPreviewHandler_TranslateAccelerator)(void* This,MSG* pmsg);
void* GetFunctionPtr(void* ptrInt,int id);
HB_FUNC( IPREVIEWHANDLER_SETWINDOW )
{
PHB_ITEM pSelf = hb_stackSelfItem();
void* ptr = hb_itemGetPtr(hb_itemArrayGet(pSelf,1));
IPreviewHandler_SetWindow* fn = (IPreviewHandler_SetWindow*)GetFunctionPtr(ptr,3);
#ifndef _WIN64
HWND hWnd = ( HWND ) hb_parnl( 1 );
#else
HWND hWnd = ( HWND ) hb_parnll( 1 );
#endif
RECT rc,*prc = NULL;
HRESULT retVal;
if( hb_param(2, HB_IT_ARRAY) != 0 )
{
rc.top = hb_parvni( 2, 1);
rc.left = hb_parvni( 2, 2);
rc.bottom = hb_parvni( 2, 3);
rc.right = hb_parvni( 2, 4);
prc = &rc;
} else prc = 0;
retVal = (*fn)(ptr,hWnd,prc);
hb_retnl(retVal);
}
HB_FUNC( IPREVIEWHANDLER_SETRECT )
{
PHB_ITEM pSelf = hb_stackSelfItem();
void* ptr = hb_itemGetPtr(hb_itemArrayGet(pSelf,1));
IPreviewHandler_SetRect* fn = (IPreviewHandler_SetRect*)GetFunctionPtr(ptr,4);
RECT rc,*prc = NULL;
HRESULT retVal;
if( hb_param(1, HB_IT_ARRAY) != 0 )
{
rc.top = hb_parvni( 1, 1);
rc.left = hb_parvni( 1, 2);
rc.bottom = hb_parvni( 1, 3);
rc.right = hb_parvni( 1, 4);
prc = &rc;
} else prc = 0;
retVal = (*fn)(ptr,prc);
hb_retnl(retVal);
}
HB_FUNC( IPREVIEWHANDLER_DOPREVIEW )
{
PHB_ITEM pSelf = hb_stackSelfItem();
void* ptr = hb_itemGetPtr(hb_itemArrayGet(pSelf,1));
IPreviewHandler_DoPreview* fn = (IPreviewHandler_DoPreview*)GetFunctionPtr(ptr,5);
HRESULT retVal;
retVal = (*fn)(ptr);
hb_retnl(retVal);
}
HB_FUNC( IPREVIEWHANDLER_UNLOAD )
{
PHB_ITEM pSelf = hb_stackSelfItem();
void* ptr = hb_itemGetPtr(hb_itemArrayGet(pSelf,1));
IPreviewHandler_Unload* fn = (IPreviewHandler_Unload*)GetFunctionPtr(ptr,6);
HRESULT retVal;
retVal = (*fn)(ptr);
hb_retnl(retVal);
}
HB_FUNC( IPREVIEWHANDLER_SETFOCUS )
{
PHB_ITEM pSelf = hb_stackSelfItem();
void* ptr = hb_itemGetPtr(hb_itemArrayGet(pSelf,1));
IPreviewHandler_SetFocus* fn = (IPreviewHandler_SetFocus*)GetFunctionPtr(ptr,7);
HRESULT retVal;
retVal = (*fn)(ptr);
hb_retnl(retVal);
}
HB_FUNC( IPREVIEWHANDLER_QUERYFOCUS )
{
PHB_ITEM pSelf = hb_stackSelfItem();
void* ptr = hb_itemGetPtr(hb_itemArrayGet(pSelf,1));
IPreviewHandler_QueryFocus* fn = (IPreviewHandler_QueryFocus*)GetFunctionPtr(ptr,7);
HWND hWnd;
HRESULT retVal;
retVal = (*fn)(ptr,&hWnd);
#ifndef _WIN64
hb_stornl((long)hWnd,1);
#else
hb_stornll((HB_LONGLONG)hWnd,1);
#endif
hb_retnl(retVal);
}
#pragma ENDDUMP
IInitializeWithFile
Code: Select all | Expand
#include <hbclass.ch>
/* From propsys.idl
[
uuid(b7d14566-0509-4cce-a71f-0a554233bd9b),
object,
pointer_default(unique)
]
interface IInitializeWithFile : IUnknown
{
HRESULT Initialize([in, string] LPCWSTR pszFilePath, [in] DWORD grfMode);
}
*/
#define IID_IInitializeWithFile {0xb7d14566,0x0509,0x4cce,0xa7,0x1f,0x0a,0x55,0x42,0x33,0xbd,0x9b}
class IInitializeWithFile FROM IUnknown
METHOD Initialize(pszFilePath,grfMode)
endclass
#pragma BEGINDUMP
#include <windows.h>
#include <hbapi.h>
#include <hbstack.h>
#include <hbapiitm.h>
/* 3*/typedef HRESULT (__stdcall *IInitializeWithFile_Initialize)(void* This,LPCWSTR pszFilePath, DWORD grfMode);
void* GetFunctionPtr(void* ptrInt,int id);
LPWSTR UTF8toUTF16( LPCSTR utf8 );
HB_FUNC( IINITIALIZEWITHFILE_INITIALIZE )
{
PHB_ITEM pSelf = hb_stackSelfItem();
void* ptr = hb_itemGetPtr(hb_itemArrayGet(pSelf,1));
IInitializeWithFile_Initialize* fn = (IInitializeWithFile_Initialize*)GetFunctionPtr(ptr,3);
LPCWSTR pszFilePath = UTF8toUTF16(hb_parc(1));
DWORD grfMode = hb_parnl(2);
HRESULT retVal;
retVal = (*fn)(ptr,pszFilePath,grfMode);
hb_xfree( (void*) pszFilePath);
hb_retnl(retVal);
}
#pragma ENDDUMP
and IInitializeWithStream
Code: Select all | Expand
#include <hbclass.ch>
/* From propsys.idl
[
uuid(b824b49d-22ac-4161-ac8a-9916e8fa3f7f),
object,
pointer_default(unique)
]
interface IInitializeWithStream : IUnknown
{
[local] HRESULT Initialize([in, annotation("_In_")] IStream *pstream, [in, annotation("_In_")] DWORD grfMode);
[call_as(Initialize)] HRESULT RemoteInitialize([in] IStream *pstream, [in] DWORD grfMode);
}*/
#define IID_IInitializeWithStream {0xb824b49d,0x22ac,0x4161,0xac,0x8a,0x99,0x16,0xe8,0xfa,0x3f,0x7f}
class IInitializeWithStream FROM IUnknown
METHOD Initialize(pstream, grfMode)
endclass
#pragma BEGINDUMP
#include <windows.h>
#include <hbapi.h>
#include <hbstack.h>
#include <hbapiitm.h>
/* 3*/typedef HRESULT (__stdcall *IInitializeWithStream_Initialize)(void* This,IStream *pstream, DWORD grfMode);
void* GetFunctionPtr(void* ptrInt,int id);
HB_FUNC( IINITIALIZEWITHSTREAM_INITIALIZE )
{
PHB_ITEM pSelf = hb_stackSelfItem();
void* ptr = hb_itemGetPtr(hb_itemArrayGet(pSelf,1));
IInitializeWithStream_Initialize* fn = (IInitializeWithStream_Initialize*)GetFunctionPtr(ptr,3);
IStream* pstream = (IStream*) hb_parptr(1);
DWORD grfMode = hb_parnl(2);
HRESULT retVal;
retVal = (*fn)(ptr,pstream,grfMode);
hb_retnl(retVal);
}
#pragma ENDDUMP
here the class that use all:
Code: Select all | Expand
#include <fivewin.ch>
#include <winapi.ch>
function main()
local oDlg
local oPreview
// IMPORTANT!!
CoInitialize()
DEFINE WINDOW oDlg FROM 0,0 TO 650,650 PIXEL TITLE "Test"
oPreview := TPreviewControl():New(30,10,oDlg, 600,600)
oPreview:AcceptDropFile()
@ 8,8 BUTTON "Clear" ACTION oPreview:Clear() PIXEL SIZE 32,16 OF oDlg
ACTIVATE WINDOW oDlg CENTERED
return nil
CLASS TPreviewControl FROM TControl
CLASSDATA lRegistered AS LOGICAL
DATA pPreview INIT 0
DATA pStream INIT 0
METHOD New( nRow, nCol, oWnd, nWidth, nHeight ) CONSTRUCTOR
METHOD Destroy()
METHOD SetFile(cFile)
METHOD AcceptDropFile()
METHOD Clear()
METHOD DropFiles( hDrop )
METHOD Resize()
METHOD Display() INLINE ::BeginPaint(), ::Paint(), ::EndPaint(), 0
ENDCLASS
METHOD New( nRow, nCol, oWnd, nWidth, nHeight ) CLASS TPreviewControl
DEFAULT nRow := 10, nCol := 10, oWnd := GetWndDefault(), nWidth := 64, nHeight := 64
::oWnd := oWnd
::nId := ::GetNewId()
::nStyle := nOR( WS_CHILD, WS_VISIBLE, WS_TABSTOP, WS_CLIPCHILDREN )
::nTop := nRow
::nLeft := nCol
::nBottom := ::nTop + nHeight - 1
::nRight := ::nLeft + nWidth
::Register( nOR( CS_VREDRAW, CS_HREDRAW ) )
::Create()
oWnd:AddControl( Self )
return Self
METHOD Destroy()
::Clear()
return ::Super:Destroy()
METHOD Clear() CLASS TPreviewControl
if valtype(::pPreview) == "O"
::pPreview:Unload()
endif
if Valtype(::pStream) == "P"
DestroyStream(::pStream)
endif
::pPreview := 0
::pStream := 0
return nil
#define HKEY_CLASSES_ROOT 2147483648 // 0x80000000
#define IID_IPreviewHandler {0x8895b1c6,0xb41f,0x4c1c,0xa5,0x62,0x0d,0x56,0x42,0x50,0x83,0x6f}
#define IID_IInitializeWithFile {0xb7d14566,0x0509,0x4cce,0xa7,0x1f,0x0a,0x55,0x42,0x33,0xbd,0x9b}
#define IID_IInitializeWithStream {0xb824b49d,0x22ac,0x4161,0xac,0x8a,0x99,0x16,0xe8,0xfa,0x3f,0x7f}
#define CLSCTX_INPROC_SERVER 0x1
#define CLSCTX_LOCAL_SERVER 0x4
METHOD SetFile(cFile) CLASS TPreviewControl
LOCAL cExtension, cKey, cid, nError, cls
LOCAL pInit
::Clear()
cExtension := substr(cFile,rat(".",cFile))
cKey = cExtension + "\ShellEx\{8895b1c6-b41f-4c1c-a562-0d564250836f}"
cid := ""
//get preview guid
nError = RegQueryValue( HKEY_CLASSES_ROOT, cKey, @cid )
if nError <> 0
cKey := Space(100)
RegQueryValue( HKEY_CLASSES_ROOT, cExtension, @cKey )
cKey := StrTran( cKey, Chr(0), "" )
cKey := Alltrim(cKey) + "\ShellEx\{8895b1c6-b41f-4c1c-a562-0d564250836f}"
nError = RegQueryValue( HKEY_CLASSES_ROOT, cKey, @cid )
endif
// crete the preview object
if nError = 0
cid := StrTran( cid, Chr(0), "" )
cls := iidFromString(cid)
nError := CoCreateInstance( cls, nOr( CLSCTX_INPROC_SERVER, CLSCTX_LOCAL_SERVER), IID_IPreviewHandler, @::pPreview )
endif
if Valtype(::pPreview) == "P"
::pPreview := IPreviewHandler():New(::pPreview)
//init the preview
::pPreview:QueryInterface(IID_IInitializeWithFile, @pInit)
if Valtype(pInit) == "P"
pInit := IInitializeWithFile():New(pInit)
pInit:Initialize(cFile, /*STGM_READ*/0)
else
::pPreview:QueryInterface(IID_IInitializeWithStream, @pInit)
if Valtype(pInit) == "P"
pInit := IInitializeWithStream():New(pInit)
::pStream := GetStream(cFile)
pInit:Initialize(::pStream, /*STGM_READ*/0)
else
::pPreview := 0
endif
endif
endif
if valtype(::pPreview) == "O"
::pPreview:SetWindow(::hWnd, GetClientRect( ::hWnd ))
::pPreview:DoPreview()
endif
return self
METHOD Resize()
::pPreview:SetRect( GetClientRect( ::hWnd ))
return self
METHOD AcceptDropFile() CLASS TPreviewControl
DragAcceptFiles( ::hWnd, .T. )
return Self
METHOD DropFiles( hDrop ) CLASS TPreviewControl
LOCAL files
files = DragQueryFiles( hDrop )
::SetFile( files[1])
return Self
#pragma BEGINDUMP
#define CINTERFACE
#define COBJMACROS
#include <Ole2.h>
#include <hbapi.h>
#include <unknwn.h>
LPWSTR UTF8toUTF16( LPCSTR utf8 );
HB_FUNC( GETSTREAM ) // cFileName
{
wchar_t* cFileName = UTF8toUTF16(hb_parc(1));
HANDLE hFile = CreateFileW(cFileName,FILE_READ_DATA,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL );
DWORD dwSize = GetFileSize( hFile, NULL );
HGLOBAL hGlobal= GlobalAlloc(GPTR, dwSize );
BYTE * pByte = (BYTE *)GlobalLock(hGlobal);
LPSTREAM pStream;
ReadFile(hFile,pByte,dwSize,&dwSize,NULL);
GlobalUnlock(hGlobal);
CloseHandle( hFile );
CreateStreamOnHGlobal(hGlobal, TRUE, &pStream);
hb_xfree( (void*) cFileName);
hb_retptr(pStream);
}
HB_FUNC( DESTROYSTREAM ) // stream
{
LPSTREAM pStream = hb_parptr(1);
HGLOBAL hGlobal;
if( pStream )
{
GetHGlobalFromStream(pStream,&hGlobal);
if(hGlobal)
GlobalFree(hGlobal);
IUnknown_Release(pStream);
}
hb_ret();
}
#pragma ENDDUMP
the TPreviewControl is re-usable.
except for the stream part I think the last file is easily understand-able, and this code should compile with borland 5 also.