...Now I see why this section described as 'not for the faint of heart.'. For a week already I am trying to implement a simple namespace handler, but only getting fault after fault.. :evil:
Anyway, I wanted to ask if anyone here ever worked with urlmon object?
I especially interested in examples of IInternetSession and other interfaces that are used in creation of asynchronous pluggable protocols.
Posted on 2004-12-11 14:29:28 by arafel
Could someone do me a favor and look at the code i have linked below. I have tried to remove all the unnecessary parts. But the size is still not so small. sorry.

Supplied dll is a name-space handler for http protocol. The system should on every url access ('http:') pass the execution to IInternetProtocol::Start. But for some reason my implementation of Start method never receives the call.

http://coronis.berlios.de/iip.zip
Posted on 2004-12-25 16:22:11 by arafel
there were some bugs in your code.
I made some minor changes and start is now executed (only if you use IE, of course)

but since uploading is deactivated in this forum, code follows here:
(you will have to delete the OutputDebugString lines, since macro
CStr isn't defined):



.486
.model flat, stdcall
option casemap:none


include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\advapi32.inc
include \masm32\include\ole32.inc
include \masm32\include\user32.inc
include \masm32\include\shlwapi.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\advapi32.lib
includelib \masm32\lib\ole32.lib
includelib \masm32\lib\shlwapi.lib
includelib \masm32\lib\uuid.lib

include macros.inc



INET_E_USE_DEFAULT_PROTOCOLHANDLER equ 800C0011h


DllRegisterServer PROTO
DllCanUnloadNow PROTO
DllGetClassObject PROTO :DWORD, :DWORD, :DWORD
DllUnregisterServer PROTO
QueryInterface PROTO :DWORD, :DWORD, :DWORD
AddRef PROTO :DWORD
Release PROTO :DWORD
CreateInstance PROTO :DWORD, :DWORD, :DWORD, :DWORD
iecm_QueryInterface PROTO :DWORD, :DWORD, :DWORD
iecm_AddRef PROTO :DWORD
iecm_Release PROTO :DWORD
iecm_Start PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
iecm_Continue PROTO :DWORD
iecm_Abort PROTO :DWORD, :DWORD
iecm_Terminate PROTO :DWORD
iecm_Suspend PROTO
iecm_Resume PROTO
iecm_Read PROTO :DWORD, :DWORD, :DWORD
iecm_Seek PROTO :DWORD, :DWORD, :DWORD
iecm_LockRequest PROTO :DWORD
iecm_UnlockRequest PROTO

externdef IID_IInternetProtocolRoot:IID
externdef IID_IInternetProtocol:IID

CFObject STRUCT
lpVtbl DWORD ?
nRefCount DWORD ?
CFObject ENDS

IECMObjectStruc STRUCT
lpVtbl DWORD ?
nRefCount DWORD ?
nValue DWORD ?
IECMObjectStruc ENDS


QueryInterfaceProto TYPEDEF PROTO :DWORD, :DWORD, :DWORD
AddRefProto TYPEDEF PROTO :DWORD
ReleaseProto TYPEDEF PROTO :DWORD
CreateInstanceProto TYPEDEF PROTO :DWORD, :DWORD, :DWORD, :DWORD
LockServerProto TYPEDEF PROTO :DWORD, :DWORD

c_QueryInterface TYPEDEF ptr QueryInterfaceProto
c_AddRef TYPEDEF ptr AddRefProto
c_Release TYPEDEF ptr ReleaseProto
c_CreateInstance TYPEDEF ptr CreateInstanceProto
c_LockServer TYPEDEF ptr LockServerProto

IClassFactory STRUCT
QueryInterface c_QueryInterface ?
AddRef c_AddRef ?
Release c_Release ?
CreateInstance c_CreateInstance ?
LockServer c_LockServer ?
IClassFactory ENDS


iecm_QueryInterfaceProto TYPEDEF PROTO :DWORD, :DWORD, :DWORD
iecm_AddRefProto TYPEDEF PROTO :DWORD
iecm_ReleaseProto TYPEDEF PROTO :DWORD
iecm_StartProto TYPEDEF PROTO :DWORD, :DWORD, :DWORD, :DWORD, :DWORD
iecm_ContinueProto TYPEDEF PROTO :DWORD
iecm_AbortProto TYPEDEF PROTO :DWORD, :DWORD
iecm_TerminateProto TYPEDEF PROTO :DWORD
iecm_SuspendProto TYPEDEF PROTO
iecm_ResumeProto TYPEDEF PROTO
iecm_ReadProto TYPEDEF PROTO :DWORD, :DWORD, :DWORD
iecm_SeekProto TYPEDEF PROTO :DWORD, :DWORD, :DWORD
iecm_LockRequestProto TYPEDEF PROTO :DWORD
iecm_UnlockRequestProto TYPEDEF PROTO

i_QueryInterface TYPEDEF ptr iecm_QueryInterfaceProto
i_AddRef TYPEDEF ptr iecm_AddRefProto
i_Release TYPEDEF ptr iecm_ReleaseProto
i_Start TYPEDEF ptr iecm_StartProto
i_Continue TYPEDEF ptr iecm_ContinueProto
i_Abort TYPEDEF ptr iecm_AbortProto
i_Terminate TYPEDEF ptr iecm_TerminateProto
i_Suspend TYPEDEF ptr iecm_SuspendProto
i_Resume TYPEDEF ptr iecm_ResumeProto
i_Read TYPEDEF ptr iecm_ReadProto
i_Seek TYPEDEF ptr iecm_SeekProto
i_LockRequest TYPEDEF ptr iecm_LockRequestProto
i_UnlockRequest TYPEDEF ptr iecm_UnlockRequestProto

IIECM STRUCT
iecm_QueryInterface i_QueryInterface ? ; IUnknown members
iecm_AddRef i_AddRef ?
iecm_Release i_Release ?
iecm_Abort i_Abort ? ; IInternetProtocolRoot members
iecm_Continue i_Continue ?
iecm_Resume i_Resume ?
iecm_Start i_Start ?
iecm_Suspend i_Suspend ?
iecm_Terminate i_Terminate ?
iecm_LockRequest i_LockRequest ? ; IInternetProtocol members
iecm_Read i_Read ?
iecm_Seek i_Seek ?
iecm_UnlockRequest i_UnlockRequest ?
IIECM ENDS



ShowProgress MACRO strng
local @l

.data
@l db strng
db 8 dup(0)

.code
pushad
mov edi, offset @l
xor eax, eax
@@: scasb
jne @b
dec edi
cmp eax, S_OK
jne notok
mov [edi], dword ptr "KO_S"
mov [edi+4], byte ptr 0
jmp @f
notok: mov [edi], dword ptr "LIAF"
mov [edi+4], word ptr "DE"
mov [edi+6], byte ptr 0
@@: invoke MessageBox, 0, ADDR @l, 0, MB_OK
popad
ENDM




.data


IECMObject CFObject <OFFSET vtIClassFactory,0>

vtIClassFactory IClassFactory <QueryInterface,AddRef,Release,CreateInstance,LockServer>
vtIMyCom IIECM <iecm_QueryInterface,iecm_AddRef,iecm_Release,iecm_Start,iecm_Continue,iecm_Abort,iecm_Terminate,\
iecm_Suspend,iecm_Resume,iecm_Read, iecm_Seek,iecm_LockRequest,iecm_UnlockRequest>

IID_IUnknown GUID {000000000h, 00000h, 00000h,{0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h}}
IID_IClassFactory GUID {000000001h, 00000h, 00000h,{0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h}}
CLSID_IECM GUID {07FC322AEh, 00971h, 04142h,{09Ch, 00Ch, 0FFh, 07Eh, 054h, 0C7h, 001h, 0A2h}}

obj_desc db "IECM service for mFIDS",0
obj_name db "IECM",0
clsid_txt db "CLSID",0
obj_GUID_txt db "{7FC322AE-0971-4142-9C0C-FF7E54C701A2}",0
InprocServer32_txt db "InprocServer32",0
ThreadingModel_txt db "ThreadingModel",0
apartment_txt db "Apartment",0
nsh_txt db "PROTOCOLS\Name-Space Handler\http\iecm",0



.data?

hInstance dd ?
curpath db MAX_PATH dup(?)



.code


;============================================================================================================
; dll entry procedure
;
; returns: EAX = TRUE/FALSE
;
;============================================================================================================
; - OK
DllMain PROC _hInstance:HANDLE, ulReason:DWORD, _Reserved:DWORD

.if ulReason == DLL_PROCESS_ATTACH

invoke OutputDebugString, CStr(<"DllMain process attach",13,10>)
mov eax, _hInstance
mov [hInstance], eax
mov eax, TRUE

.elseif ulReason == DLL_PROCESS_DETACH

invoke OutputDebugString, CStr(<"DllMain thread attach",13,10>)
mov eax, FALSE

.elseif ulReason == DLL_THREAD_ATTACH

mov eax, FALSE

.elseif ulReason == DLL_THREAD_DETACH

mov eax, FALSE

.else

mov eax, FALSE

.endif

ret

DllMain ENDP



;============================================================================================================
; check if service is ready for unload
;
; returns: EAX = S_OK/S_FALSE
;
;============================================================================================================

DllCanUnloadNow PROC

cmp [IECMObject.nRefCount], 0
je @f
mov eax, S_FALSE
ret
@@: mov eax, S_OK
ret

DllCanUnloadNow ENDP



;============================================================================================================
; gets class object from dll object handler
;
; returns: EAX = CLASS_E_CLASSNOTAVAILABLE/S_OK/E_NOINTERFACE
;
;============================================================================================================

DllGetClassObject PROC rclsid:DWORD, piid:DWORD, ppv:DWORD


invoke OutputDebugString, CStr(<"DllGetClassObject",13,10>)
invoke IsEqualGUID, rclsid, ADDR CLSID_IECM

.if eax == TRUE

invoke OutputDebugString, CStr(<"DllGetClassObject, CLSID ok",13,10>)
invoke QueryInterface, ADDR IECMObject, piid, ppv
push eax
.if (eax == S_OK)
invoke OutputDebugString, CStr(<"DllGetClassObject, IID ok",13,10>)
.else
invoke OutputDebugString, CStr(<"DllGetClassObject, IID not ok",13,10>)
.endif

invoke Release, offset IECMObject
pop eax


.else

mov eax, CLASS_E_CLASSNOTAVAILABLE

.endif

ret


DllGetClassObject ENDP



;============================================================================================================
; registers the COM object
;
; returns: EAX = 0 on success. API function return value otherwise.
;
;============================================================================================================

DllRegisterServer PROC

Local hKey:DWORD
Local hKey2:DWORD
Local hKey3:DWORD


invoke RegCreateKey, HKEY_CLASSES_ROOT, ADDR obj_name, ADDR hKey ; [HKEY_CLASSES_ROOT\CMyCom]
cmp eax, ERROR_SUCCESS ; @="IECM service for mFIDS"
jne @ret
invoke RegSetValue, hKey, 0, REG_SZ, ADDR obj_desc, sizeof obj_desc
cmp eax, ERROR_SUCCESS
jne @ret

invoke RegCreateKey, hKey, ADDR clsid_txt, ADDR hKey2 ; [HKEY_CLASSES_ROOT\CMyCom\CLSID]
cmp eax, ERROR_SUCCESS ; @="{A21A8C42-1266-11D4-A324-0040F6D487D9}"
jne @ret

invoke RegSetValue, hKey2, 0, REG_SZ, ADDR obj_GUID_txt, sizeof obj_GUID_txt
cmp eax, ERROR_SUCCESS
jne @ret

invoke RegCloseKey, hKey
invoke RegCloseKey, hKey2


invoke RegCreateKey, HKEY_CLASSES_ROOT, ADDR clsid_txt, ADDR hKey ; [HKEY_CLASSES_ROOT\CLSID\'GUID']
cmp eax, ERROR_SUCCESS ; @="IECM service for mFIDS"
jne @ret

invoke RegCreateKey, hKey, ADDR obj_GUID_txt, ADDR hKey2
cmp eax, ERROR_SUCCESS
jne @ret

invoke RegSetValue, hKey2, 0, REG_SZ, ADDR obj_desc, sizeof obj_desc
cmp eax, ERROR_SUCCESS
jne @ret


invoke RegCreateKey, hKey2, ADDR obj_name, ADDR hKey3 ; [HKEY_CLASSES_ROOT\CLSID\'GUID'\CMyCom]
cmp eax, ERROR_SUCCESS ; @="CMyCom"
jne @ret

invoke RegSetValue, hKey3, 0, REG_SZ, ADDR obj_name, sizeof obj_name
cmp eax, ERROR_SUCCESS
jne @ret

invoke RegCloseKey, hKey3


invoke GetModuleFileName, hInstance, ADDR curpath, MAX_PATH
cmp eax, 4
jbe @ret

invoke RegCreateKey, hKey2, ADDR InprocServer32_txt, ADDR hKey3 ;[HKEY_CLASSES_ROOT\CLSID\'GUID'\InprocServer32]
cmp eax, ERROR_SUCCESS ; @="fullpathto\iecm.dll"
jne @ret ; "ThreadingModel"="Both"

invoke RegSetValue, hKey3, 0, REG_SZ, ADDR curpath, MAX_PATH
cmp eax, ERROR_SUCCESS
jne @ret

invoke RegSetValueEx, hKey3, ADDR ThreadingModel_txt, 0, REG_SZ, ADDR apartment_txt, sizeof apartment_txt
cmp eax, ERROR_SUCCESS
jne @ret

invoke RegCloseKey, hKey3
invoke RegCloseKey, hKey2
invoke RegCloseKey, hKey


invoke RegCreateKey, HKEY_CLASSES_ROOT, ADDR nsh_txt, ADDR hKey ; [HKEY_CLASSES_ROOT\
cmp eax, ERROR_SUCCESS ; PROTOCOLS\Name-Space Handler\http\iecm]
jne @ret ; "iecm"='GUID'

invoke RegSetValueEx, hKey, ADDR clsid_txt, 0, REG_SZ, ADDR obj_GUID_txt, sizeof obj_GUID_txt
cmp eax, ERROR_SUCCESS
jne @ret

invoke RegCloseKey, hKey

xor eax, eax
@ret: ret

DllRegisterServer ENDP



;============================================================================================================
; unregisters the COM object
;
; returns: EAX = 0 on success. API function return value otherwise.
;
;============================================================================================================

DllUnregisterServer PROC

Local hKey:DWORD

invoke SHDeleteKey, HKEY_CLASSES_ROOT, ADDR obj_name

invoke RegOpenKey, HKEY_CLASSES_ROOT, ADDR clsid_txt, ADDR hKey
cmp eax, ERROR_SUCCESS
jne @ret

invoke SHDeleteKey, hKey, ADDR obj_GUID_txt

xor eax, eax
@ret: ret

DllUnregisterServer ENDP



;============================================================================================================
; returns a pointer to a specific interface (IClassFactory)
;
; returns: EAX = S_OK\E_NOINTERFACE
;
;============================================================================================================

QueryInterface PROC this_:DWORD, iid:DWORD, ppvObject:DWORD

invoke IsEqualGUID, iid, ADDR IID_IClassFactory
push eax
invoke IsEqualGUID, iid, ADDR IID_IUnknown
pop edx
or eax, edx

.if eax == TRUE
mov eax, this_
mov edx, ppvObject
mov [edx], eax
invoke AddRef, eax
mov eax, S_OK
ret
.endif

mov [ppvObject], 0
mov eax, E_NOINTERFACE
ret

QueryInterface ENDP



;============================================================================================================
; increments reference count (IClassFactory)
;
; returns: EAX = current reference count
;
;============================================================================================================

AddRef PROC this_:DWORD

inc [IECMObject.nRefCount]
mov eax, [IECMObject.nRefCount]
ret

AddRef ENDP



;============================================================================================================
; decrements reference count (IClassFactory)
;
; returns: EAX = current reference count
;
;============================================================================================================

Release proc this_:DWORD

dec [IECMObject.nRefCount]
mov eax, [IECMObject.nRefCount]
ret

Release endp



;============================================================================================================
; creates an object (IClassFactory)
;
; returns: EAX = E_OUTOFMEMORY\pointer to com object
;
;============================================================================================================

CreateInstance PROC uses ebx this_:DWORD, pUnkOuter:DWORD, riid:DWORD, ppvObject:DWORD

invoke CoTaskMemAlloc, sizeof IECMObjectStruc
test eax, eax
je memout

mov (IECMObjectStruc PTR [eax]).lpVtbl, offset vtIMyCom
mov (IECMObjectStruc PTR [eax]).nRefCount, 1
mov (IECMObjectStruc PTR [eax]).nValue, 0

inc [IECMObject.nRefCount]

mov ebx, eax
invoke iecm_QueryInterface, eax, riid, ppvObject

push eax
.if (eax == S_OK)
invoke OutputDebugString, CStr(<"CreateInstance OK",13,10>)
.else
invoke OutputDebugString, CStr(<"CreateInstance not OK",10,10>)
.endif
pop eax
; ShowProgress "(IClassFactory)CreateInstance -> (IIECM)iecm_QueryInterface = "

push eax
invoke iecm_Release, ebx
pop eax
ret

memout:
invoke OutputDebugString, CStr(<"CreateInstance OUTOFMEMORY",13,10>)
mov eax, E_OUTOFMEMORY
ret

CreateInstance ENDP



;============================================================================================================
; keeps the server open in memory
;
; returns: EAX = always S_OK
;
;============================================================================================================

LockServer PROC fLock:DWORD

.if fLock == TRUE

inc [IECMObject.nRefCount]

.else

dec [IECMObject.nRefCount]

.endif

mov eax, S_OK
ret

LockServer ENDP



;============================================================================================================
; returns a pointer to a specific interface (IIECM)
;
; returns:
;
;============================================================================================================

iecm_QueryInterface PROC this_:DWORD, iid:DWORD, ppvObject:DWORD

invoke IsEqualGUID, iid, ADDR IID_IUnknown
.if (eax != TRUE)
invoke IsEqualGUID, iid, ADDR IID_IInternetProtocolRoot
.if (eax != TRUE)
invoke IsEqualGUID, iid, ADDR IID_IInternetProtocol
.endif
.endif
.if (eax == TRUE)
mov eax, this_
mov edx, ppvObject
mov [edx], eax
invoke iecm_AddRef, eax
invoke OutputDebugString, CStr(<"iecm_QueryInterface OK",13,10>)
mov eax, S_OK
ret
.endif

mov edx, ppvObject
mov [edx], dword ptr 0
invoke OutputDebugString, CStr(<"iecm_QueryInterface failed",13,10>)
mov eax, E_NOINTERFACE
ret

iecm_QueryInterface endp



;============================================================================================================
; increments reference count (IIECM)
;
; returns: EAX = current reference count
;
;============================================================================================================

iecm_AddRef PROC this_:DWORD

mov eax, this_
inc (IECMObjectStruc ptr [eax]).nRefCount
mov eax, (IECMObjectStruc ptr [eax]).nRefCount
ret

iecm_AddRef ENDP



;============================================================================================================
; decrements reference count (IIECM)
;
; returns: EAX = current reference count
;
;============================================================================================================

iecm_Release PROC this_:DWORD

mov eax, this_
dec (IECMObjectStruc ptr [eax]).nRefCount
mov eax, (IECMObjectStruc ptr [eax]).nRefCount
test eax, eax
jne @ret

invoke CoTaskMemFree, this_
dec [IECMObject.nRefCount]
xor eax, eax
@ret: ret

iecm_Release ENDP



;============================================================================================================
; IInternetProtocol::Start
;
; returns: should return INET_E_USE_DEFAULT_PROTOCOLHANDLER or S_OK
;
;============================================================================================================

iecm_Start PROC szUrl:DWORD, OIProtSink:DWORD, OIBindInfo:DWORD, grfPI:DWORD, dwReserved:DWORD

invoke OutputDebugString, CStr(<"(IIECM)IInternetProtocol::Start - ",13,10>)

mov eax, INET_E_USE_DEFAULT_PROTOCOLHANDLER
ret

iecm_Start ENDP


;============================================================================================================
; IInternetProtocol::Read
;
; returns: EAX = always S_OK
;
;============================================================================================================

iecm_Read PROC pv:DWORD, cb:DWORD, cbRead:DWORD

mov eax, S_OK
ret

iecm_Read ENDP


;============================================================================================================
; IInternetProtocol::Terminate
;
; returns: EAX = always S_OK
;
;============================================================================================================

iecm_Terminate PROC dwOptions:DWORD

mov eax, S_OK
ret

iecm_Terminate ENDP


;============================================================================================================
; IInternetProtocol::LockRequest
;
; returns: EAX = always S_OK
;
;============================================================================================================

iecm_LockRequest PROC dwOptions:DWORD

mov eax, S_OK
ret
iecm_LockRequest ENDP


;============================================================================================================
; IInternetProtocol::UnlockRequest
;
; returns: EAX = always S_OK
;
;============================================================================================================

iecm_UnlockRequest PROC

mov eax, S_OK
ret

iecm_UnlockRequest ENDP


;============================================================================================================
; IInternetProtocol::Continue
;
; returns: EAX = always S_OK
;
;============================================================================================================

iecm_Continue PROC ProtocolData:DWORD

mov eax, S_OK
ret

iecm_Continue ENDP


;============================================================================================================
; IInternetProtocol::Abort
;
; returns: EAX = always E_NOTIMPL
;
;============================================================================================================

iecm_Abort PROC hrReason:DWORD, dwOptions:DWORD

mov eax, E_NOTIMPL
ret

iecm_Abort ENDP


;============================================================================================================
; IInternetProtocol::Suspend
;
; returns: EAX = always E_NOTIMPL
;
;============================================================================================================

iecm_Suspend PROC

mov eax, E_NOTIMPL
ret

iecm_Suspend ENDP


;============================================================================================================
; IInternetProtocol::Resume
;
; returns: EAX = always E_NOTIMPL
;
;============================================================================================================

iecm_Resume PROC

mov eax, E_NOTIMPL
ret

iecm_Resume ENDP


;============================================================================================================
; IInternetProtocol::Seek
;
; returns: EAX = always E_NOTIMPL
;
;============================================================================================================

iecm_Seek PROC dlibMove:DWORD, dwOrigin:DWORD, libNewPosition:DWORD

mov eax, E_NOTIMPL
ret

iecm_Seek ENDP


end DllMain
Posted on 2004-12-26 05:44:53 by japheth
exactly as i suspected - dumb mistakes prevented start to execute.. :oops:

i didn't know that IInternetProtocol\Root IIDs should be checked in QueryInterface though.

thanks japheth!
Posted on 2004-12-28 15:32:48 by arafel