COM のオブジェクトはクラスなど使わなくても、QueryInterface などの各メソッドへのアドレスを列挙した配列 (仮想関数テーブル) と、それへのアドレスを適切にメモリに配置するだけで成り立ちます。

HSP3 にはクラスや構造体を実装する機能はありませんが、コールバック用の関数アドレスを生成するプラグインとメモリ操作命令があります。これらを活用することで HSP3 でも COM インターフェースの実装ができます。
その実証のためにエクスプローラー ビューである IExplorerBrowser のコールバック インターフェース IExplorerBrowserEvents を実装してみました。IExplorerBrowser はビューが生成されたりナビゲーションが発生した場合に IExplorerBrowserEvents の対応するメソッドを呼び出します。
今回のサンプルではフォルダーなどをクリックしてナビゲーションを発生させるとタイトルバーに情報が表示されるようにしています。それとなぜかフォルダーをダブルクリックすると別窓が開いてしまうのでコンテキスト メニューから 2 番目の 開く コマンドを選択する必要があります。

コード
※hscallbk が必要
#include "hscallbk.as" #define NULL 0 #define S_OK 0 #define E_INVALIDARG 0x80070057 #define E_NOINTERFACE 0x80004002 #define CLSCTX_INPROC_SERVER 1 #define FVM_AUTO -1 #define FVM_FIRST 1 #define FVM_ICON 1 #define FVM_SMALLICON 2 #define FVM_LIST 3 #define FVM_DETAILS 4 #define FVM_THUMBNAIL 5 #define FVM_TILE 6 #define FVM_THUMBSTRIP 7 #define FVM_CONTENT 8 #define FVM_LAST 8 #define FWF_FULLROWSELECT 0x200000 #define SBSP_DEFBROWSER 0x0000 #define SBSP_SAMEBROWSER 0x0001 #define SBSP_NEWBROWSER 0x0002 #define SBSP_DEFMODE 0x0000 #define SBSP_OPENMODE 0x0010 #define SBSP_EXPLOREMODE 0x0020 #define SBSP_HELPMODE 0x0040 #define SBSP_NOTRANSFERHIST 0x0080 #define SBSP_ABSOLUTE 0x0000 #define SBSP_RELATIVE 0x1000 #define SBSP_PARENT 0x2000 #define SBSP_NAVIGATEBACK 0x4000 #define SBSP_NAVIGATEFORWARD 0x8000 #define SHGFI_DISPLAYNAME 0x000000200 #define SHGFI_PIDL 0x000000008 #uselib "msvcrt" #cfunc malloc "malloc" int #func free "free" int #cfunc memcmp "memcmp" int, int, int #uselib "kernel32" #func InterlockedIncrement "InterlockedIncrement" int #func InterlockedDecrement "InterlockedDecrement" int #uselib "shell32" #func SHGetFileInfoA "SHGetFileInfoA" int, int, int, int, int #func SHParseDisplayName "SHParseDisplayName" wptr, int, int, int, int #uselib "ole32" #func CLSIDFromString "CLSIDFromString" wptr, int #func CoCreateInstance "CoCreateInstance" int, int, int, int, int #func CoTaskMemFree "CoTaskMemFree" int // IExplorerBrowserEvents 用の仮想関数テーブルを作る #uselib "" #func IExplorerBrowserEvents_QueryInterface "" int, int, int setcallbk CExplorerBrowserEvents_QueryInterface, IExplorerBrowserEvents_QueryInterface, *FnCExplorerBrowserEvents_QueryInterface #func IExplorerBrowserEvents_AddRef "" int setcallbk CExplorerBrowserEvents_AddRef, IExplorerBrowserEvents_AddRef, *FnCExplorerBrowserEvents_AddRef #func IExplorerBrowserEvents_Release "" int setcallbk CExplorerBrowserEvents_Release, IExplorerBrowserEvents_Release, *FnCExplorerBrowserEvents_Release #func IExplorerBrowserEvents_OnNavigationPending "" int, int setcallbk CExplorerBrowserEvents_OnNavigationPending, IExplorerBrowserEvents_OnNavigationPending, *FnCExplorerBrowserEvents_OnNavigationPending #func IExplorerBrowserEvents_OnViewCreated "" int, int setcallbk CExplorerBrowserEvents_OnViewCreated, IExplorerBrowserEvents_OnViewCreated, *FnCExplorerBrowserEvents_OnViewCreated #func IExplorerBrowserEvents_OnNavigationComplete "" int, int setcallbk CExplorerBrowserEvents_OnNavigationComplete, IExplorerBrowserEvents_OnNavigationComplete, *FnCExplorerBrowserEvents_OnNavigationComplete #func IExplorerBrowserEvents_OnNavigationFailed "" int, int setcallbk CExplorerBrowserEvents_OnNavigationFailed, IExplorerBrowserEvents_OnNavigationFailed, *FnCExplorerBrowserEvents_OnNavigationFailed dim CExplorerBrowserEventsVtbl, 7 CExplorerBrowserEventsVtbl(0) = varptr(CExplorerBrowserEvents_QueryInterface) CExplorerBrowserEventsVtbl(1) = varptr(CExplorerBrowserEvents_AddRef) CExplorerBrowserEventsVtbl(2) = varptr(CExplorerBrowserEvents_Release) CExplorerBrowserEventsVtbl(3) = varptr(CExplorerBrowserEvents_OnNavigationPending) CExplorerBrowserEventsVtbl(4) = varptr(CExplorerBrowserEvents_OnViewCreated) CExplorerBrowserEventsVtbl(5) = varptr(CExplorerBrowserEvents_OnNavigationComplete) CExplorerBrowserEventsVtbl(6) = varptr(CExplorerBrowserEvents_OnNavigationFailed) /* CExplorerBrowserEvents メモリ レイアウト 0 4 void* CExplorerBrowserEventsVtbl 4 4 ULONG m_refCount 8 4 DWORD m_cookie */ #define SizeOfCExplorerBrowserEvents 12 #define CExplorerBrowserEvents_Vtbl 0 #define CExplorerBrowserEvents_RefCount 4 #define CExplorerBrowserEvents_Cookie 8 #module // オブジェクトとメソッド番号からメソッドの関数アドレスを取得する便利関数 #defcfunc getMethodAddr int pObj, int index dupptr _pObjVtbl, pObj, 4, 4 dupptr _pMethod, _pObjVtbl + 4 * index, 4, 4 return _pMethod #global // 文字列から GUID 構造体に変換 dim CLSID_ExplorerBrowser, 4 CLSIDFromString "{71f96385-ddd6-48d3-a0c1-ae06e8b055fb}", varptr(CLSID_ExplorerBrowser) dim IID_IUnknown, 4 CLSIDFromString "{00000000-0000-0000-C000-000000000046}", varptr(IID_IUnknown) dim IID_IExplorerBrowser, 4 CLSIDFromString "{dfd3b6b5-c10c-4be9-85f6-a66969f402f6}", varptr(IID_IExplorerBrowser) dim IID_IExplorerBrowserEvents, 4 CLSIDFromString "{361bbdc7-e6ee-4e13-be58-58e2240c810f}", varptr(IID_IExplorerBrowserEvents) // エクスプローラー ブラウザーを作成 pExplorerBrowser = 0 hr = CoCreateInstance(varptr(CLSID_ExplorerBrowser), NULL, CLSCTX_INPROC_SERVER, varptr(IID_IExplorerBrowser), varptr(pExplorerBrowser)) if (pExplorerBrowser == 0) { mes "pExplorerBrowser is null" stop } // ブラウザー初期化 rect = 0, 26, ginfo_winx, ginfo_winy fs = FVM_DETAILS, FWF_FULLROWSELECT prms = pExplorerBrowser, hwnd, varptr(rect), varptr(fs) hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 3) /* IExplorerBrowser_Initialize */, length(prms)) // コールバック登録 pExplorerBrowserEvents = NewCExplorerBrowserEvents() prms = pExplorerBrowser, pExplorerBrowserEvents, pExplorerBrowserEvents + CExplorerBrowserEvents_Cookie hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 9) /* IExplorerBrowser_Advise */, length(prms)) // フォルダーへ移動 pIdList = 0 SHParseDisplayName "C:\\", NULL, varptr(pIdList), 0, NULL // ファイル パスから IDLIST へ変換 prms = pExplorerBrowser, pIdList, SBSP_DEFBROWSER hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 13) /* IExplorerBrowser_BrowseToIDList */, length(prms)) CoTaskMemFree pIdList pIdList = 0 objsize 50, 26 pos 0, 0: button gosub "戻る", *goBack pos 50, 0: button gosub "進む", *goForward pos 100, 0: button gosub "上へ", *goParent onexit *exit stop *goBack prms = pExplorerBrowser, NULL, SBSP_NAVIGATEBACK hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 13) /* IExplorerBrowser_BrowseToIDList */, length(prms)) return *goForward prms = pExplorerBrowser, NULL, SBSP_NAVIGATEFORWARD hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 13) /* IExplorerBrowser_BrowseToIDList */, length(prms)) return *goParent prms = pExplorerBrowser, NULL, SBSP_PARENT hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 13) /* IExplorerBrowser_BrowseToIDList */, length(prms)) return *exit if (pExplorerBrowser) { prms = pExplorerBrowser hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 4) /* IExplorerBrowser_Destroy */, length(prms)) prms = pExplorerBrowser hr = callfunc(prms, getMethodAddr(pExplorerBrowser, 2) /* IExplorerBrowser_Release */, length(prms)) pExplorerBrowser = 0 } end // ----------------------------------------- // CExplorerBrowserEvents メンバー関数の実装 // ----------------------------------------- *FnCExplorerBrowserEvents_QueryInterface // params: This, riid, ppvObject if (callbkarg(2) == 0) { // ppvObject が NULL return E_INVALIDARG } dupptr pvObject, callbkarg(2), 4, 4 pvObject = 0 // IID_IUnknown か IID_IExplorerBrowserEvents ならインターフェース変換可能 if (memcmp(varptr(IID_IUnknown), callbkarg(1), 4) == 0 || memcmp(varptr(IID_IExplorerBrowserEvents), callbkarg(1), 4) == 0) { pvObject = callbkarg(0) prms = callbkarg(0) hr = callfunc(prms, getMethodAddr(callbkarg(0), 1) /* IExplorerBrowserEvents_AddRef */, length(prms)) return S_OK } return E_NOINTERFACE *FnCExplorerBrowserEvents_AddRef // params: This return InterlockedIncrement(callbkarg(0) + CExplorerBrowserEvents_RefCount) *FnCExplorerBrowserEvents_Release // params: This ref = InterlockedDecrement(callbkarg(0) + CExplorerBrowserEvents_RefCount) if (ret == 0) { // CExplorerBrowserEvents クラスを破棄 free callbkarg(0) return 0 } return ref *FnCExplorerBrowserEvents_OnNavigationPending // params: This, pidlFolder title "ナビゲーション中..." return S_OK *FnCExplorerBrowserEvents_OnViewCreated // params: This, psv return S_OK *FnCExplorerBrowserEvents_OnNavigationComplete // params: This, pidlFolder // 現在のフォルダー名をタイトルバーに表示させてみる sdim fi, 360 // SHFILEINFOA if (SHGetFileInfoA(callbkarg(1), 0, varptr(fi), 360, SHGFI_DISPLAYNAME | SHGFI_PIDL)) { sdim szDisplayName getstr szDisplayName, fi, 12, '0', 260 title "成功: " + szDisplayName } return S_OK *FnCExplorerBrowserEvents_OnNavigationFailed // params: This, pidlFolder title "失敗" return S_OK #defcfunc NewCExplorerBrowserEvents // CExplorerBrowserEvents クラスを構築 pObj = malloc(SizeOfCExplorerBrowserEvents) dupptr _obj, pObj, SizeOfCExplorerBrowserEvents, 4 _obj(0) = varptr(CExplorerBrowserEventsVtbl) // CExplorerBrowserEventsVtbl _obj(1) = 1 // m_refCount _obj(2) = 0 // m_cookie return pObj