Beispiel 4) Erstellen einer selbstregistrierenden Com-Dll mit Dualinterfacemit dem code eine dll erstellen (unicode nicht vergessen) und dann die dll mit regsvr32 registrieren
Rechnen.pbCode:
EnableExplicit
;------ Konstanten -----
#RechnenPlus = 101
#RechnenMinus = 102
;;=
;------ Strukturen -----
Structure udtClassFactory
*VTable
cntRef.l
cntLock.l
*oOwn.IUnknown
EndStructure
Structure udtApplication
*VTable
cntRef.l
*oOwn.IUnknown
*oPar.IUnknown
*oApp.IUnknown
EndStructure
Structure EXCEPINFO
wCode.w
wReserved.w
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64 : padding1.b[4] : CompilerEndIf
bstrSource.s
bstrDescription.s
bstrHelpFile.s
dwHelpContext.l
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64 : padding2.b[4] : CompilerEndIf
*pvReserved
*pfnDeferredFillIn
sCode.l
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64 : padding3.b[4] : CompilerEndIf
EndStructure
;;=
;------ Deklarationen -----
Declare.d AP_RechnenPlus (*This, a.d, b.d, *res=0)
Declare.d AP_RechnenMinus (*This, a.d, b.d, *res=0)
;;=
;-===== ENTWICKLUNGS PROZEDUREN ===================================================================
;Was hier steht, kann vor dem kompilieren der endgültigen DLL gelöscht werden
Procedure ShowGuidString(*Guid.GUID)
Define msg.s
msg + RSet (Hex(*Guid\Data1 , #PB_Long), 8, "0") + "-"
msg + RSet (Hex(*Guid\Data2 , #PB_Word), 4, "0") + "-"
msg + RSet (Hex(*Guid\Data3 , #PB_Word), 4, "0") + "-"
msg + RSet (Hex(*Guid\Data4[0], #PB_Byte), 2, "0")
msg + RSet (Hex(*Guid\Data4[1], #PB_Byte), 2, "0") + "-"
msg + RSet (Hex(*Guid\Data4[2], #PB_Byte), 2, "0")
msg + RSet (Hex(*Guid\Data4[3], #PB_Byte), 2, "0")
msg + RSet (Hex(*Guid\Data4[4], #PB_Byte), 2, "0")
msg + RSet (Hex(*Guid\Data4[5], #PB_Byte), 2, "0")
msg + RSet (Hex(*Guid\Data4[6], #PB_Byte), 2, "0")
msg + RSet (Hex(*Guid\Data4[7], #PB_Byte), 2, "0")
SetClipboardText (msg)
MessageRequester ("IID-String", msg + #CRLF$ + #CRLF$ + "Der IID-String wurde in die Zwischenablage kopiert")
EndProcedure
;;=================================================================================================
;-===== DLL PROZEDUREN ============================================================================
ProcedureDLL AttachProcess(Instanz)
EndProcedure
ProcedureDLL DetachProcess(Instanz)
EndProcedure
ProcedureDLL AttachThread (Instanz)
EndProcedure
ProcedureDLL DetachThread (Instanz)
EndProcedure
;;=================================================================================================
;-===== COM PROZEDUREN ============================================================================
ProcedureDLL.l DllRegisterServer ()
Define ProgrammId.s
Define KlassenId.s
Define Beschreibung.s
Define DllName.s
Define hKey.l
Define ret.l
ProgrammId = "Rechnen.Application"
KlassenId = "{BC2F3427-426C-4B9F-A695-761A58D79A33}"
Beschreibung = "Pb - Rechnen mit COM-DLL"
DllName = ProgramFilename()
ret + RegCreateKeyEx_(#HKEY_CLASSES_ROOT, ProgrammId, 0, 0, #REG_OPTION_NON_VOLATILE, #KEY_ALL_ACCESS, 0, @hKey, 0)
ret + RegSetValueEx_ (hKey, "", 0, #REG_SZ, Beschreibung, StringByteLength(Beschreibung) + 2)
ret + RegCloseKey_ (hKey)
ret + RegCreateKeyEx_(#HKEY_CLASSES_ROOT, ProgrammId + "\CLSID", 0, 0, #REG_OPTION_NON_VOLATILE, #KEY_ALL_ACCESS, 0, @hKey, 0)
ret + RegSetValueEx_ (hKey, "", 0, #REG_SZ, KlassenId, StringByteLength(KlassenId) + 2)
ret + RegCloseKey_ (hKey)
ret + RegCreateKeyEx_(#HKEY_CLASSES_ROOT, "CLSID\" + KlassenId, 0, 0, #REG_OPTION_NON_VOLATILE, #KEY_ALL_ACCESS, 0, @hKey, 0)
ret + RegSetValueEx_ (hKey, "", 0, #REG_SZ, Beschreibung, StringByteLength(Beschreibung) + 2)
ret + RegCloseKey_ (hKey)
ret + RegCreateKeyEx_(#HKEY_CLASSES_ROOT, "CLSID\" + KlassenId + "\InprocServer32", 0, 0, #REG_OPTION_NON_VOLATILE, #KEY_ALL_ACCESS, 0, @hKey, 0)
ret + RegSetValueEx_ (hKey, "", 0, #REG_SZ, DllName, StringByteLength(DllName) + 2)
ret + RegCloseKey_ (hKey)
ret + RegCreateKeyEx_(#HKEY_CLASSES_ROOT, "CLSID\" + KlassenId + "\ProgId", 0, 0, #REG_OPTION_NON_VOLATILE, #KEY_ALL_ACCESS, 0, @hKey, 0)
ret + RegSetValueEx_ (hKey, "", 0, #REG_SZ, Beschreibung, StringByteLength(Beschreibung) + 2)
ret + RegCloseKey_ (hKey)
If ret
ProcedureReturn #SELFREG_E_CLASS
EndIf
EndProcedure
ProcedureDLL.l DllUnregisterServer()
Define ProgrammId.s
Define KlassenId.s
Define ret.l
ProgrammId = "Rechnen.Application"
KlassenId = "{BC2F3427-426C-4B9F-A695-761A58D79A33}"
ret + RegDeleteKey_(#HKEY_CLASSES_ROOT, "CLSID\" + KlassenId + "\ProgId")
ret + RegDeleteKey_(#HKEY_CLASSES_ROOT, "CLSID\" + KlassenId + "\InprocServer32")
ret + RegDeleteKey_(#HKEY_CLASSES_ROOT, "CLSID\" + KlassenId)
ret + RegDeleteKey_(#HKEY_CLASSES_ROOT, ProgrammId + "\CLSID")
ret + RegDeleteKey_(#HKEY_CLASSES_ROOT, ProgrammId)
If ret
ProcedureReturn #SELFREG_E_CLASS
EndIf
EndProcedure
ProcedureDLL.l DllGetClassObject (*rclsid.IID, *riid.iid, *ppvObject.Integer)
Define *oNew.udtClassFactory
If CompareMemory(*rclsid, ?CLSID_Rechnen, 16)
If CompareMemory(*riid, ?IID_IClassFactory, 16)
;Klassenobjekt erstellen
*oNew = AllocateMemory (SizeOf(udtClassFactory))
*oNew\VTABLE = ?VT_ClassFactory
*oNew\oOwn = *oNew
*ppvObject\i = *oNew : *oNew\oOwn\AddRef()
ProcedureReturn #S_OK
EndIf
EndIf
;Unbekannte Klasse
MessageRequester ("DLL", "DllGetClassObject hat nach einer unbekannten Klasse angefragt")
*ppvObject\i = 0
ProcedureReturn #CLASS_E_CLASSNOTAVAILABLE
EndProcedure
ProcedureDLL.l DllCanUnloadNow ()
EndProcedure
;;=================================================================================================
;-===== CLASS FACTORY =============================================================================
Procedure.l CF_QueryInterface (*This.udtClassFactory, *iid.IID, *Object.Integer)
;Standardzuweisungen auf eigenes Objekt
If CompareMemory(*iid, ?IID_IUnknown, 16) Or CompareMemory(*iid, ?IID_IDispatch, 16) Or CompareMemory(*iid, ?IID_IClassFactory, 16)
*Object\i = *This : *This\oOwn\AddRef()
ProcedureReturn #S_OK
EndIf
;IClassFactoryEx ist momentan nicht implementiert
If CompareMemory(*iid, ?IID_IClassFactoryEx, 16)
*Object\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
;Unbekanntes Interface
MessageRequester("CF" , "QueryInterface hat nach einem nicht impletierten Interface angefragt")
*Object\i = 0
ProcedureReturn #E_NOINTERFACE
EndProcedure
Procedure.l CF_AddRef (*This.udtClassFactory)
*This\cntRef + 1
ProcedureReturn *This\cntRef
EndProcedure
Procedure.l CF_Release (*This.udtClassFactory)
;Wenn Referenzzähler nicht auf 0 kommt
If *This\cntRef > 1
*This\cntRef - 1
ProcedureReturn *This\cntRef
EndIf
;Eigenes Objekt auflösen
FreeMemory(*This)
MessageRequester ("CF", "AUFGELÖST")
ProcedureReturn 0
EndProcedure
Procedure.l CF_CreateInstance (*This.udtClassFactory, *pUnkOuter, *riid.IID, *ppvObject.Integer)
Define *oNew.udtApplication
;Aggregation wird momentan nicht unterstützt
If *pUnkOuter
MessageRequester ("CF", "Aggregation wird nicht unterstützt")
*ppvObject\i = 0
ProcedureReturn #CLASS_E_NOAGGREGATION
EndIf
;Eine neues Applikationsobjekt erstellen
If CompareMemory(*riid, ?IID_IUnknown, 16) Or CompareMemory(*riid, ?IID_IDispatch, 16)
*oNew = AllocateMemory (SizeOf(udtApplication))
*oNew\VTable = ?VT_Application
*oNew\oOwn = *oNew
*oNew\oPar = *oNew
*oNew\oApp = *oNew
*ppvObject\i = *oNew : *oNew\oOwn\AddRef()
ProcedureReturn #S_OK
EndIf
;Nicht implementierte Klasse wurde angefragt
MessageRequester ("CF", "Unbekannte Klasse wurde angefragt")
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndProcedure
Procedure.l CF_LockServer (*This.udtClassFactory, fLock.b)
If fLock = #False
*This\cntLock - 1
Else
*This\cntLock + 1
EndIf
ProcedureReturn #S_OK
EndProcedure
;;=================================================================================================
;-===== CLASS APPLICATION =========================================================================
Procedure.l AP_QueryInterface (*This.udtApplication, *iid.IID, *Object.Integer)
;Standardzuweisungen auf eigenes Objekt
If CompareMemory(*iid, ?IID_IUnknown, 16) Or CompareMemory(*iid, ?IID_IDispatch, 16)
*Object\i = *This : *This\oOwn\AddRef()
ProcedureReturn #S_OK
EndIf
;IDispatchEx ist momentan nicht implementiert
If CompareMemory(*iid, ?IID_IDispatchEx, 16)
*Object\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
;IObjectWithSite ist momentan nicht implementiert
If CompareMemory(*iid, ?IID_IObjectWithSite, 16)
*Object\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
;IPersistStreamInit ist momentan nicht implementiert
If CompareMemory(*iid, ?IID_IPersistStreamInit, 16)
*Object\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
;IPersistPropertyBag ist momentan nicht implementiert
If CompareMemory(*iid, ?IID_IPersistPropertyBag, 16)
*Object\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
;Unbekanntes Interface
MessageRequester("App" , "QueryInterface hat nach einem nicht implementierten Interface angefragt")
*Object\i = 0
ProcedureReturn #E_NOINTERFACE
EndProcedure
Procedure.l AP_AddRef (*This.udtApplication)
*This\cntRef + 1
ProcedureReturn *This\cntRef
EndProcedure
Procedure.l AP_Release (*This.udtApplication)
;Wenn Referenzzähler nicht auf 0 kommt
If *This\cntRef > 1
*This\cntRef - 1
ProcedureReturn *This\cntRef
EndIf
;Eigenes Objekt auflösen
FreeMemory(*This)
MessageRequester ("AP", "AUFGELÖST")
ProcedureReturn 0
EndProcedure
Procedure.l AP_GetTypeInfoCount (*This.udtApplication, *CntTypeInfo.Long)
*CntTypeInfo\l = 0
ProcedureReturn #S_OK
EndProcedure
Procedure.l AP_GetTypeInfo (*This.udtApplication, TypeInfo.l, LocalId.l, *ppTypeInfo.Integer)
ProcedureReturn #S_OK
EndProcedure
Procedure.l AP_GetIDsOfNames (*This.udtApplication, *iid.IID, *Name.String, cntNames.l, lcid.l, *DispId.Long)
If *Name\s = "RechnenPlus" : *DispId\l = #RechnenPlus : EndIf
If *Name\s = "RechnenMinus" : *DispId\l = #RechnenMinus : EndIf
EndProcedure
Procedure.l AP_Invoke (*This.udtApplication, DispId.l, *iid.IID, lcid.l, Flags.w, *DispParams.DISPPARAMS, *vResult.VARIANT, *ExcepInfo.EXCEPINFO, *ArgErr.Integer)
Dim vArg.VARIANT(20)
CopyMemory (*DispParams\rgvarg, @vArg(), 20 * SizeOf(VARIANT))
VariantChangeType_(vArg(0), vArg(0), 0, #VT_R8)
VariantChangeType_(vArg(1), vArg(1), 0, #VT_R8)
Select DispId
Case #RechnenPlus : *vResult\vt = #VT_R8 : *vResult\dblVal = AP_RechnenPlus (*This, vArg(1)\dblVal, vArg(0)\dblVal)
Case #RechnenMinus : *vResult\vt = #VT_R8 : *vResult\dblVal = AP_RechnenMinus (*This, vArg(1)\dblVal, vArg(0)\dblVal)
EndSelect
EndProcedure
Procedure.d AP_RechnenPlus (*This.udtApplication, a.d, b.d, *res.Double=0)
Define result.d
result = a + b
If *res : *res\d = result : EndIf
ProcedureReturn result
EndProcedure
Procedure.d AP_RechnenMinus (*This.udtApplication, a.d, b.d, *res.Double=0)
Define result.d
result = a - b
If *res : *res\d = result : EndIf
ProcedureReturn result
EndProcedure
;;=================================================================================================
;-===== DATA SECTION ==============================================================================
DataSection
VT_ClassFactory:
Data.i @CF_QueryInterface()
Data.i @CF_AddRef()
Data.i @CF_Release()
Data.i @CF_CreateInstance()
Data.i @CF_LockServer()
VT_Application:
Data.i @AP_QueryInterface()
Data.i @AP_AddRef()
Data.i @AP_Release()
Data.i @AP_GetTypeInfoCount()
Data.i @AP_GetTypeInfo()
Data.i @AP_GetIDsOfNames()
Data.i @AP_Invoke()
Data.i @AP_RechnenPlus()
Data.i @AP_RechnenMinus()
CLSID_Rechnen: ; {BC2F3427-426C-4B9F-A695-761A58D79A33}
Data.l $BC2F3427
Data.w $426C,$4B9F
Data.b $A6,$95,$76,$1A,$58,$D7,$9A,$33
IID_IUnknown: ; {00000000-0000-0000-C000-000000000046}
Data.l $00000000
Data.w $0000,$0000
Data.b $C0,$00,$00,$00,$00,$00,$00,$46
IID_IDispatch: ; {00020400-0000-0000-C000-000000000046}
Data.l $00020400
Data.w $0000,$0000
Data.b $C0,$00,$00,$00,$00,$00,$00,$46
IID_IDispatchEx: ; {A6EF9860-C720-11D0-9337-00A0C90DCAA9}
Data.l $A6EF9860
Data.w $C720,$11D0
Data.b $93,$37,$00,$A0,$C9,$0D,$CA,$A9
IID_IClassFactory: ; {00000001-0000-0000-C000-000000000046}
Data.l $00000001
Data.w $0000,$0000
Data.b $C0,$00,$00,$00,$00,$00,$00,$46
IID_IClassFactoryEx: ; {342D1EA0-AE25-11D1-89C5-006008C3FBFC}
Data.l $342D1EA0
Data.w $AE25,$11D1
Data.b $89,$C5,$00,$60,$08,$C3,$FB,$FC
IID_IObjectWithSite: ; {FC4801A3-2BA9-11CF-A229-00AA003D7352}
Data.l $FC4801A3
Data.w $2BA9,$11CF
Data.b $A2,$29,$00,$AA,$00,$3D,$73,$52
IID_IPersistStreamInit: ; {7FD52380-4E07-101B-AE2D-08002B2EC713}
Data.l $7FD52380
Data.w $4E07,$101B
Data.b $AE,$2D,$08,$00,$2B,$2E,$C7,$13
IID_IPersistPropertyBag: ; {37D84F60-42CB-11CE-8135-00AA004BB851}
Data.l $37D84F60
Data.w $42CB,$11CE
Data.b $81,$35,$00,$AA,$00,$4B,$B8,$51
EndDataSection
;;=================================================================================================