From 23062cdd5a6fa571ea95e96f82f937ea16983072 Mon Sep 17 00:00:00 2001 From: Imhotheb Date: Fri, 19 Apr 2019 19:04:35 +0200 Subject: [PATCH] Version 1.00.190419 Initial Version Signed-off-by: Imhotheb --- .gitignore | 16 + COMatePLUS/COMatePLUS.chm | Bin 0 -> 117845 bytes COMatePLUS/COMatePLUS.pbi | 2572 +++++++++++++++++++++++++++ COMatePLUS/COMatePLUS_Residents.pbi | 143 ++ DYMO.pbi | 732 ++++++++ DYMO_CreateDLL.pb | 13 + DYMO_DLL.pbi | 116 ++ DYMO_Example.pb | 188 ++ LICENSE | 41 +- README.md | 44 +- Sample_101x54.label | 204 +++ Sample_89x28.label | 200 +++ Sample_Logo.bmp | Bin 0 -> 3382 bytes 13 files changed, 4267 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 COMatePLUS/COMatePLUS.chm create mode 100644 COMatePLUS/COMatePLUS.pbi create mode 100644 COMatePLUS/COMatePLUS_Residents.pbi create mode 100644 DYMO.pbi create mode 100644 DYMO_CreateDLL.pb create mode 100644 DYMO_DLL.pbi create mode 100644 DYMO_Example.pb create mode 100644 Sample_101x54.label create mode 100644 Sample_89x28.label create mode 100644 Sample_Logo.bmp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..72a297d --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# ignore PureBasic projects +*.pbp + +# ignore binary files +*.exe +*.dll +*.lib +*.obj + +# ignore temporary files +*.exp +*.tmp +*.temp + +# other +*.bak diff --git a/COMatePLUS/COMatePLUS.chm b/COMatePLUS/COMatePLUS.chm new file mode 100644 index 0000000000000000000000000000000000000000..bf0881d6bbba13cc80e00f96ad1ded429e3f7206 GIT binary patch literal 117845 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%0AX$-#X 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 literal 0 HcmV?d00001 diff --git a/COMatePLUS/COMatePLUS.pbi b/COMatePLUS/COMatePLUS.pbi new file mode 100644 index 0000000..e2ec68b --- /dev/null +++ b/COMatePLUS/COMatePLUS.pbi @@ -0,0 +1,2572 @@ +CompilerIf Defined(INCLUDE_COMATE, #PB_Constant)=0 +#INCLUDE_COMATE=1 +;///////////////////////////////////////////////////////////////////////////////// +;***COMate*** COM automation through iDispatch. +;*=========== +;* +;*COMatePLUS. Version 1.2 released 09th July 2010. +;* +;*©nxSoftWare (www.nxSoftware.com) 2009. +;*====================================== +;* With thanks to ts-soft, kiffi, mk-soft. +;* The EventSink code is based on that produced by Freak : http://www.purebasic.fr/english/viewtopic.php?t=26744&postdays=0&postorder=asc&start=75 +;* Created with Purebasic 4.3 for Windows. +;* +;* Platforms: Windows. +;///////////////////////////////////////////////////////////////////////////////// + +;///////////////////////////////////////////////////////////////////////////////// +;*NOTES. +; i) This code has arisen from my study of COM automation; the mechanism through which applications can +; connect to COM servers through what is termed 'late binding'. +; +; ii) At present this can only be used for servers on the local machine. + +; iii) This code is based upon the DispHelper sourcecode : http://disphelper.sourceforge.net/. +; +; iv) Define the constant #COMATE_NOINCLUDEATL = 1 before including this source to remove all ActiveX code from this library. +; Useful for NT in which the ATL library may not be present. +; +; v) Define the constant #COMATE_NOERRORREPORTING = 1 before including this source to remove all error reporting. Might be useful if +; looking to squeeze a little more speed out of your code! +;///////////////////////////////////////////////////////////////////////////////// + +XIncludeFile "COMatePLUS_Residents.pbi" + +;-IMPORTS. + CompilerIf Defined(COMATE_NOINCLUDEATL, #PB_Constant)=0 + Import "atl.lib" + AtlAxCreateControl(lpszName,hWnd.i,*pStream.IStream,*ppUnkContainer.IUnknown) + AtlAxGetControl(hWnd.i,*pp.IUnknown) + AtlAxGetHost(hWnd, *pp.IUnknown) + AtlAxWinInit() + EndImport + CompilerEndIf + +;-PROTOTYPES. + ;The following prototype caters for Ansi / Unicode when creating BSTR's. + Prototype.i COMate_ProtoMakeBSTR(value.p-unicode) + ;The following is for any automation servers opting to defer filling in EXCEPINFO2 structures in the case of a dispinterface + ;function yielding an error etc. In these cases a callback is provided by the server which we call manually. + Prototype.i COMate_ProtoDeferredFillIn(*EXCEPINFO2) + ;The following prototypes allow for various return types from event handlers. + Prototype COMate_EventCallback_NORETURN(COMateObject.COMateObject, EventName$, ParameterCount) + Prototype.q COMate_EventCallback_INTEGERRETURN(COMateObject.COMateObject, EventName$, ParameterCount) + Prototype.d COMate_EventCallback_REALRETURN(COMateObject.COMateObject, EventName$, ParameterCount) + Prototype.s COMate_EventCallback_STRINGRETURN(COMateObject.COMateObject, EventName$, ParameterCount) + Prototype COMate_EventCallback_UNKNOWNRETURN(COMateObject.COMateObject, EventName$, ParameterCount, *returnValue.VARIANT) + +;-CONSTANTS (private) + #COMate_MAXNUMSUBOBJECTS = 20 ;Used for nested object calls; e.g. "Cells(1, 2)\Value = 'COMate'" + #COMate_MAXNUMSYMBOLSINALINE = 200 + #COMate_MAXNUMVARIANTARGS = 20 ;The max number of arguments which can be passed to a single COM method. + Enumeration + #CLSCTX_INPROC_SERVER = 1 + #CLSCTX_INPROC_HANDLER = 2 + #CLSCTX_LOCAL_SERVER = 4 + #CLSCTX_REMOTE_SERVER = 16 + #CLSCTX_FROM_DEFAULT_CONTEXT = $20000 + #CLSCTX_SERVER = (#CLSCTX_INPROC_SERVER | #CLSCTX_LOCAL_SERVER | #CLSCTX_REMOTE_SERVER) + EndEnumeration + + Enumeration ;Used when parsing command strings and setting up the variant array. + #COMate_Operator + #COMate_Operand + #COMate_OpenParanthesis + #COMate_CloseParanthesis + #COMate_Method + EndEnumeration + + #DISPID_PROPERTYPUT = -3 ;The iDisp value for property put calls to iDispatch\Invoke() which require a single named parameter. + #DISPID_NEWENUM = -4 ;The iDisp value for propertyget calls in which a new enumeration is being requested. + + #CONNECT_E_ADVISELIMIT = -2147220991 + +;-STRUCTURES. + + ;The following structure contains the class template and private properties for the main COMateObject. + Structure _membersCOMateClass + *vTable + iDisp.iDispatch + containerID.i + hWnd.i + *eventSink._COMateEventSink + EndStructure + + ;The following structure contains the class template and private properties for the COMateEnumObject. + Structure _membersCOMateEnumClass + *vTable + *parent._membersCOMateClass ;Points to the COMate Object which is hosting this enumeration. Used for error reporting. + iEV.IEnumVARIANT + EndStructure + + ;The following structure is used in thread local storage to store info on the latest error recorded by an object within the current thread. + Structure _COMateThreadErrors + lastErrorCode.i + lastError$ + EndStructure + + ;The following structure holds a COMatePLUS 'statement' object representing a compiled command string. + ;A statement handle is simply a pointer to one of these structures. + Structure _COMatePLUSStatement + numSubObjects.i + methodName.i[#COMate_MAXNUMSUBOBJECTS+1] ;1-based indexing. BSTRs. + numArgs.i[#COMate_MAXNUMSUBOBJECTS+1] ;1-based indexing. + ptrVarArgs.i[#COMate_MAXNUMSUBOBJECTS+1] ;1-based indexing. + EndStructure + + ;The following structure is used in an array when parsing method parameters etc. + Structure _COMateParse + numberOfTokens.i + numOpenBrackets.i + numCloseBrackets.i + tokens$[#COMate_MAXNUMSYMBOLSINALINE] + EndStructure + + ;The following structure is used in the iDispatch\Invoke() method call to receive detailed errors. + CompilerIf Defined(EXCEPINFO2, #PB_Structure) = 0 + CompilerIf #PB_Compiler_Processor = #PB_Processor_x64 + Structure EXCEPINFO2 + wCode.w + wReserved.w + pad.b[4] ; Only on x64 + bstrSource.i ;BSTR + bstrDescription.i + bstrHelpFile.i + dwHelpContext.l + pvReserved.i + pfnDeferredFillIn.COMate_ProtoDeferredFillIn + scode.l + pad2.b[4] ; Only on x64 + EndStructure + CompilerElse + Structure EXCEPINFO2 + wCode.w + wReserved.w + bstrSource.i ;BSTR + bstrDescription.i + bstrHelpFile.i + dwHelpContext.l + pvReserved.i + pfnDeferredFillIn.COMate_ProtoDeferredFillIn + scode.l + EndStructure + CompilerEndIf + CompilerEndIf + + ;The following structure is used when connecting an outgoing interface (sink) to a COM object's connection point. + Structure _COMateEventSink + *Vtbl + refCount.i + cookie.i + connIID.IID + typeInfo.ITypeInfo + Callback.COMate_EventCallback_NORETURN + returnType.i + *dispParams.DISPPARAMS + *parent._membersCOMateClass ;A pointer back to the parent COMate object so that we can pass this to the event procedure. + EndStructure + + +;-MACROS + + ;The following two macros are used to test for success or failure when calling com methods. + ;They are pretty superfluous really but do aid readability. + Macro SUCCEEDED(HRESULT) + HRESULT & $80000000 = 0 + EndMacro + Macro FAILED(HRESULT) + HRESULT & $80000000 + EndMacro + + +;-DECLARES. + Declare.i COMate_INTERNAL_CheckNumeric(arg$, *var.VARIANT) + Declare COMate_INTERNAL_EscapeString(ptrText) + Declare.i COMateClass_INTERNAL_InvokePlus(*this._membersCOMateClass, invokeType, returnType, *ret.VARIANT, command$, *hStatement._COMatePLUSStatement) + Declare COMate_INTERNAL_FreeStatementHandle(*hStatement._COMatePLUSStatement) + Declare.i COMate_INTERNAL_PrepareStatement(command$, *ptrStatement.INTEGER) + Declare.i COMatePLUS_TokeniseCommand(command$, separator$, Array parse._COMateParse(1)) + Declare.i COMatePLUS_CompileSubobjectInvokation(*hStatement._COMatePLUSStatement, subObjectIndex, Array parse._COMateParse(1)) + + Declare COMateClass_INTERNAL_SetError(*this._membersCOMateClass, result, blnAllowDispError = 0, dispError$="") + Declare.i COMateClass_UTILITY_MakeBSTR(value) + + Declare.i COMateClass_GetObjectProperty(*this._membersCOMateClass, command$, *hStatement=0, objectType = #VT_DISPATCH) + + CompilerIf Defined(COMATE_NOINCLUDEATL, #PB_Constant)=0 + Declare.i COMate_DelSinkPropsCallback(hWnd, lpszString, hData,dwData) + CompilerEndIf + +;-GLOBALS. + Global COMate_MakeBSTR.COMate_ProtoMakeBSTR = @COMateClass_UTILITY_MakeBSTR() ;Prototype. + Global COMate_gErrorTLS.i ;A TLS index used to store per-thread error info. + Global COMate_gNumObjects.i ;Used to manage the error-TLS index. + Global COMate_gPtrThreadArray.i ;A pointer to an array of pointers to _COMateThreadErrors structures. + Global COMate_gNumThreadElements.i + Global COMate_gAtlAXIsInit.i + +;-======================= +;-COMate OBJECT CODE. +;-======================= + +;///////////////////////////////////////////////////////////////////////////////// +;The following function creates a new instance of a COMate object which itself contains a COM object (iDispatch). +;Change the optional parameter blnInitCOM to #False if COM has already been initialised. +;Returns the new COMate object or zero if an error. +Procedure.i COMate_CreateObject(progID$, hWnd = 0, blnInitCOM = #True) + Protected *this._membersCOMateClass, clsid.CLSID, hResult, cf.IClassFactory, progID, container.iUnknown, iDisp + If blnInitCOM + CoInitialize_(0) + EndIf + If progID$ + progID = COMate_MakeBSTR(progID$) + If progID + *this = AllocateMemory(SizeOf(_membersCOMateClass)) + If *this + *this\vTable = ?VTable_COMateClass + If hWnd = 0 ;No ActiveX control to house. + ;Get classID from the registry. + If Left(progID$, 1) = "{" + hResult = CLSIDFromString_(progID, @clsid) + If SUCCEEDED(hResult) + hResult = ProgIDFromCLSID_(clsid, @iDisp) + If SUCCEEDED(hResult) And iDIsp + SysFreeString_(iDisp) + EndIf + EndIf + Else + hResult = CLSIDFromProgID_(progID, @clsid); + EndIf + If SUCCEEDED(hResult) + hResult = CoGetClassObject_(clsid, #CLSCTX_LOCAL_SERVER|#CLSCTX_INPROC_SERVER, 0, ?IID_IClassFactory, @cf) + If SUCCEEDED(hResult) + hResult = cf\CreateInstance(0, ?IID_IDispatch, @*this\iDisp) + If FAILED(hResult) + hResult = cf\CreateInstance(0, ?IID_IUnknown, @container) + If SUCCEEDED(hResult) + hResult = container\QueryInterface(?IID_IDispatch, @*this\iDisp) + container\Release() + EndIf + EndIf + If FAILED(hResult) + FreeMemory(*this) + *this = 0 + Else; Success. + COMate_gNumObjects+1 + EndIf + Else + FreeMemory(*this) + *this = 0 + EndIf + If cf + cf\Release() + EndIf + Else + FreeMemory(*this) + *this = 0 + EndIf +CompilerIf Defined(COMATE_NOINCLUDEATL, #PB_Constant)=0 + Else ;An ActiveX control requires housing. + ;Get classID from the registry. This is a simple check to ensure the control is registered. Otherwise ATL will embed a browser in our container. + If Left(progID$, 1) = "{" + hResult = CLSIDFromString_(progID, @clsid) + If SUCCEEDED(hResult) + hResult = ProgIDFromCLSID_(clsid, @iDisp) + If SUCCEEDED(hResult) And iDIsp + SysFreeString_(iDisp) + EndIf + EndIf + Else + hResult = CLSIDFromProgID_(progID, @clsid); + EndIf + If SUCCEEDED(hResult) + If COMate_gAtlAXIsInit = #False + If AtlAxWinInit() + COMate_gAtlAXIsInit = #True + Else + hresult = #E_FAIL + FreeMemory(*this) + *this = 0 + EndIf + EndIf + If COMate_gAtlAXIsInit + hResult = AtlAxCreateControl(ProgId, hWnd, 0, 0) + If SUCCEEDED(hResult) + hResult = AtlAxGetControl(hWnd, @*this\iDisp) + If SUCCEEDED(hResult) + hresult = *this\iDisp\QueryInterface(?IID_IDispatch, @iDisp) + *this\iDisp\Release() + If SUCCEEDED(hresult) + *this\hWnd = hWnd + *this\iDisp = iDisp + COMate_gNumObjects+1 + Else + FreeMemory(*this) + *this = 0 + EndIf + Else + FreeMemory(*this) + *this = 0 + EndIf + Else + FreeMemory(*this) + *this = 0 + EndIf + EndIf + Else + FreeMemory(*this) + *this = 0 + EndIf +CompilerEndIf + EndIf + Else + hresult = #E_OUTOFMEMORY + EndIf + SysFreeString_(progID) + Else + hresult = #E_OUTOFMEMORY + EndIf + Else + hresult = #E_INVALIDARG + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, hResult) + CompilerEndIf + ProcedureReturn *this +EndProcedure +;================================================================================= + + +;///////////////////////////////////////////////////////////////////////////////// +;The following function is used either to load an instance of a com object from a file (or based upon the filename given), or to +;create a new instance of a currently active object. +;If file$ is empty, the function attempts to create a new COMate object containing a new instance of a currently active object +;(the existing COM object's reference count is increased). +;If file$ is not empty, progID$ is used to specify the class of the object in cases where the file contains multiple objects. +;(This mimicks VB's GetObject() function.) +;Returns the new COMate object or zero if an error. +Procedure.i COMate_GetObject(file$, progID$="", blnInitCOM = #True) + Protected *this._membersCOMateClass, hResult = #E_OUTOFMEMORY, iPersist.IPERSISTFILE, clsid.CLSID, cf.IClassFactory, iUnknown.IUNKNOWN + Protected bstr1, t1 + If blnInitCOM + CoInitialize_(0) + EndIf + If file$ Or progID$ + *this = AllocateMemory(SizeOf(_membersCOMateClass)) + If *this + *this\vTable = ?VTable_COMateClass + If file$ + If progID$ = "" + ;Here we attempt to create an object based upon the filename only. + bstr1 = COMate_MakeBSTR(file$) + If bstr1 ;If an error then hResult already equals #E_OUTOFMEMORY! + hResult = CoGetObject_(bstr1, 0, ?IID_IDispatch, @*this\iDisp) + SysFreeString_(bstr1) + EndIf + Else + ;Here we attempt to create an object based upon the filename and the progID. + bstr1 = COMate_MakeBSTR(progID$) + If bstr1 + hResult = CLSIDFromProgID_(bstr1, @clsid) + If SUCCEEDED(hResult) + hResult = CoGetClassObject_(clsid, #CLSCTX_LOCAL_SERVER|#CLSCTX_INPROC_SERVER, 0, ?IID_IClassFactory, @cf) + If SUCCEEDED(hResult) + hResult = cf\CreateInstance(0, ?IID_IPersistFile, @iPersist) + If SUCCEEDED(hResult) + hResult = iPersist\Load(file$, 0) + If SUCCEEDED(hResult) + hResult = iPersist\QueryInterface(?IID_IDispatch, @*this\iDisp) + EndIf + EndIf + If iPersist + iPersist\Release() + EndIf + EndIf + If cf + cf\Release() + EndIf + EndIf + EndIf + If bstr1 + SysFreeString_(bstr1) + EndIf + EndIf + Else + ;Here we attempt to create a new COMate object containing a new instance of a currently active object. + bstr1 = COMate_MakeBSTR(progID$) + If bstr1 + If Left(progID$, 1) = "{" + hResult = CLSIDFromString_(bstr1, @clsid) + If SUCCEEDED(hResult) + hResult = ProgIDFromCLSID_(clsid, @t1) + If SUCCEEDED(hResult) And t1 + SysFreeString_(t1) + EndIf + EndIf + Else + hResult = CLSIDFromProgID_(bstr1, @clsid); + EndIf + If SUCCEEDED(hResult) + hResult = GetActiveObject_(clsid, 0, @iUnknown) + If SUCCEEDED(hResult) + hResult = iUnknown\QueryInterface(?IID_IDispatch, @*this\iDisp) + EndIf + If iUnknown + iUnknown\Release() + EndIf + EndIf + SysFreeString_(bstr1) + EndIf + EndIf + EndIf + Else + hResult = #E_INVALIDARG + EndIf + If SUCCEEDED(hResult) + COMate_gNumObjects+1 + ElseIf *this + FreeMemory(*this) + *this = 0 + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, hResult) + CompilerEndIf + ProcedureReturn *this +EndProcedure +;================================================================================= + + +;///////////////////////////////////////////////////////////////////////////////// +;The following function creates a new instance of a COMate object from an object supplied directly from the user. +;This object is in the form of a iUnknown pointer to which we use QueryInterface() in an attempt to locate an iDispatch pointer. +;Useful for event procedures attached to ActiveX controls in which some parameters may be a 'raw' COM object. This function can be used to package that +;object up into the form of a COMate object. +;Returns the new COMate object or zero if an error. +Procedure.i COMate_WrapCOMObject(object.iUnknown) + Protected *this._membersCOMateClass, hResult, iDisp.iUnknown + If object + hresult = object\QueryInterface(?IID_IDispatch, @iDisp) + If SUCCEEDED(hresult) + *this = AllocateMemory(SizeOf(_membersCOMateClass)) + If *this + *this\vTable = ?VTable_COMateClass + *this\iDisp = iDisp + COMate_gNumObjects+1 + Else + hresult = #E_OUTOFMEMORY + iDisp\Release() + EndIf + EndIf + Else + hresult = #E_INVALIDARG + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, hResult) + CompilerEndIf + ProcedureReturn *this +EndProcedure +;================================================================================= + + +;///////////////////////////////////////////////////////////////////////////////// +;The following function creates a new instance of a COMate object which itself contains a COM object (iDispatch) representing an +;ActiveX server. The underlying ActiveX control is placed within a container gadget. +;Change the optional parameter blnInitCOM to #False if COM has already been initialised. +;Returns the new COMate object or zero if an error. +Procedure.i COMate_CreateActiveXControl(x, y, width, height, progID$, blnInitCOM = #True) + Protected *this._membersCOMateClass, hResult, id, hWnd, iDisp +CompilerIf Defined(COMATE_NOINCLUDEATL, #PB_Constant)=0 + If progID$ + id = ContainerGadget(#PB_Any, x, y, width, height) + CloseGadgetList() + If id + hWnd = GadgetID(id) + *this = COMate_CreateObject(progID$, hWnd, blnInitCOM) ;This procedure will set any HRESULT codes. + If *this + SetWindowLong_(hWnd, #GWL_STYLE, GetWindowLong_(hWnd, #GWL_STYLE)|#WS_CLIPCHILDREN) + *this\containerID = ID + *this\hWnd = hWnd + Else ;Cannot locate an iDispatch interface. + FreeGadget(id) + EndIf + ProcedureReturn *this + Else + hResult = #E_OUTOFMEMORY + EndIf + Else + hresult = #E_INVALIDARG + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, hResult) + CompilerEndIf +CompilerEndIf + ProcedureReturn 0 +EndProcedure +;================================================================================= + + + +;-COMate CLASS METHODS. +;---------------------------------------------- + +;================================================================================= +;The following method calls a dispinterface method where no return value is required. +;Returns a HRESULT value. #S_OK for no errors. +Procedure.i COMateClass_Invoke(*this._membersCOMateClass, command$, *hStatement=0) + Protected result.i = #S_OK + If command$ Or *hStatement + result = COMateClass_INTERNAL_InvokePlus(*this, #DISPATCH_METHOD, #VT_EMPTY, 0, command$, *hStatement) + Else + result = #E_INVALIDARG + EndIf + ;Set any error code. iDispatch errors will already have been set. + If result = -1 + result = #S_FALSE + Else + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + EndIf + ProcedureReturn result +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method releases a com object created by any of the functions which return object pointers. +;Any sink interface connected to the underlying COM object will automatically be disconnected, resulting in the +;Release() method being called and able to tidy up. +Procedure COMateClass_Release(*this._membersCOMateClass) + Protected *error._COMateThreadErrors, i.i, sink.IDispatch + If *this\iDisp ;Just in case. + ;Release underlying iDispatch object. + *this\iDisp\Release() + EndIf + If *this\containerID ;OCX controls. + FreeGadget(*this\containerID) +;We have to assume that the container will call the release() method on the connection point. +; ElseIf *this\eventSink +; sink = *this\eventSink +; sink\Release() + EndIf + COMate_gNumObjects-1 + If COMate_gNumObjects = 0 + ;Here, in the anticipation that no more objects will be created, we release all memory associated with the TLS index. + ;We recreate all this later on if required. + If COMate_gErrorTLS <> -1 + For i = 0 To COMate_gNumThreadElements-1 + *error = PeekI(COMate_gPtrThreadArray + i*SizeOf(i)) + If *error ;Just in case! + ClearStructure(*error, _COMateThreadErrors) + FreeMemory(*error) + EndIf + Next + FreeMemory(COMate_gPtrThreadArray) + COMate_gPtrThreadArray = 0 + COMate_gNumThreadElements = 0 + TlsFree_(COMate_gErrorTLS) + COMate_gErrorTLS = -1 + EndIf + EndIf + ;Free object. + FreeMemory(*this) +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method creates a new instance of a COMateEnum object based upon an enumeration applied to the underlying COMate object. +;Returns the new COMateEnum object or zero if an error. +Procedure.i COMateClass_CreateEnumeration(*this._membersCOMateClass, command$, *hStatement=0) + Protected result.i = #S_OK, *object._membersCOMateEnumClass, *tempCOMateObject._membersCOMateClass, iDisp.IDISPATCH + Protected dp.DISPPARAMS, excep.EXCEPINFO2, var.VARIANT + *object = AllocateMemory(SizeOf(_membersCOMateEnumClass)) + If *object + *object\vTable = ?VTable_COMateEnumClass + *object\parent = *this + If command$ + *tempCOMateObject = COMateClass_GetObjectProperty(*this, command$, *hStatement, #VT_DISPATCH) ;This will set any error codes etc. + If *tempCOMateObject + iDisp = *tempCOMateObject\iDisp + Else + FreeMemory(*object) + ProcedureReturn 0 ;Error codes already set. + EndIf + Else + iDisp = *this\iDisp + EndIf + result = iDisp\Invoke(#DISPID_NEWENUM, ?IID_NULL, #LOCALE_USER_DEFAULT, #DISPATCH_METHOD | #DISPATCH_PROPERTYGET, dp, var, excep, 0) + If command$ + COMateClass_Release(*tempCOMateObject) + EndIf + If SUCCEEDED(result) + Select var\vt + Case #VT_DISPATCH + result = var\pdispVal\QueryInterface(?IID_IEnumVARIANT, @*object\iEV) + Case#VT_UNKNOWN + result = var\punkVal\QueryInterface(?IID_IEnumVARIANT, @*object\iEV) + Default + result = #E_NOINTERFACE; + EndSelect + If FAILED(result) + FreeMemory(*object) + *object = 0 + EndIf + Else + If result = #DISP_E_EXCEPTION + ;Has the automation server deferred from filling in the EXCEPINFO2 structure? + If excep\pfnDeferredFillIn + excep\pfnDeferredFillIn(excep) + EndIf + If excep\bstrSource + SysFreeString_(excep\bstrSource) + EndIf + If excep\bstrDescription + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result, #True, PeekS(excep\bstrDescription, -1, #PB_Unicode)) + CompilerEndIf + SysFreeString_(excep\bstrDescription) + Else + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result, #True) + CompilerEndIf + EndIf + If excep\bstrHelpFile + SysFreeString_(excep\bstrHelpFile) + EndIf + EndIf + FreeMemory(*object) + *object = 0 + EndIf + VariantClear_(var) + Else + result = #E_OUTOFMEMORY + EndIf + ;Set any error code. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn *object +EndProcedure +;================================================================================= + + +;================================================================================= +;Returns the COMate object's underlying iDispatch object pointer. +;AddRef() is called on this object and so the developer must call Release() at some point. +Procedure.i COMateClass_GetCOMObject(*this._membersCOMateClass) + Protected result.i = #S_OK, id.i + *this\iDisp\AddRef() + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, #S_OK) + CompilerEndIf + ProcedureReturn *this\iDisp +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method returns, in the case of an ActiveX control, either the handle of the container used to house the control +;or the Purebasic gadget#. Returning the gadget# is only viable if using COMate as a source code include (or a Tailbitten library!) +Procedure.i COMateClass_GetContainerhWnd(*this._membersCOMateClass, returnCtrlID=0) + Protected result.i = #S_OK, id.i +CompilerIf Defined(COMATE_NOINCLUDEATL, #PB_Constant)=0 + If *this\hWnd + id = *this\containerID + If returnCtrlID = 0 + id = *this\hWnd + EndIf + Else + result = #E_FAIL + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn id +CompilerEndIf +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method attempts to set (or clear) the design time mode of the container. +Procedure.i COMateClass_SetDesignTimeMode(*this._membersCOMateClass, state=#True) + Protected result.i = #S_OK, id, iUnk.IUnknown, iDisp.IDispatch, comate.COMateObject +CompilerIf Defined(COMATE_NOINCLUDEATL, #PB_Constant)=0 + If *this\containerID + id = *this\containerID + result = AtlAxGetHost(GadgetID(*this\containerID), @iUnk) + If iUnk + result = iUnk\QueryInterface(?IID_IAxWinAmbientDispatch, @iDisp) + If iDisp + comate = COMate_WrapCOMObject(iDisp) + If comate + If state + result = comate\SetProperty("UserMode = #False") + Else + result = comate\SetProperty("UserMode = #True") + EndIf + comate\Release() + Else + result = COMate_GetLastErrorCode() + EndIf + iDisp\Release() + iUnk\Release() + ProcedureReturn result + EndIf + iUnk\Release() + EndIf + Else + result = #E_FAIL + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf +CompilerEndIf + ProcedureReturn result +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method calls a dispinterface function and returns a PB (system) date value. +;Any HRESULT return value is accessible through the GetLastErrorCode() method. +Procedure.i COMateClass_GetDateProperty(*this._membersCOMateClass, command$, *hStatement=0) + Protected result.i = #S_OK, retVar.VARIANT, retValue + If command$ Or *hStatement + result = COMateClass_INTERNAL_InvokePlus(*this, #DISPATCH_PROPERTYGET|#DISPATCH_METHOD, #VT_DATE, retVar, command$, *hStatement) + If SUCCEEDED(result) + retValue = (retVar\date - 25569) * 86400 + EndIf + VariantClear_(retVar) + Else + result = #E_INVALIDARG + EndIf + ;Set any error code. iDispatch errors will alreay have been set. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn retValue +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method calls a dispinterface function and returns an integer value. +;Any HRESULT return value is accessible through the GetLastErrorCode() method. +Procedure.q COMateClass_GetIntegerProperty(*this._membersCOMateClass, command$, *hStatement=0) + Protected result.i = #S_OK, retVar.VARIANT, retValue.q + If command$ Or *hStatement + If OSVersion() <= #PB_OS_Windows_2000 + result = COMateClass_INTERNAL_InvokePlus(*this, #DISPATCH_PROPERTYGET|#DISPATCH_METHOD, #VT_I4, retVar, command$, *hStatement) + Else + result = COMateClass_INTERNAL_InvokePlus(*this, #DISPATCH_PROPERTYGET|#DISPATCH_METHOD, #VT_I8, retVar, command$, *hStatement) + EndIf + If SUCCEEDED(result) + If OSVersion() <= #PB_OS_Windows_2000 + retValue = retVar\lval + Else + retValue = retVar\llval + EndIf + EndIf + VariantClear_(retVar) + Else + result = #E_INVALIDARG + EndIf + ;Set any error code. iDispatch errors will alreay have been set. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn retValue +EndProcedure +;================================================================================= + + +;================================================================================= +;Returns a COMate object or an iUnknown interface pointer depending on the value of the 'objectType' parameter. +;For 'regular' objects based upon iDispatch, leave the optional parameter 'objectType' as it is. +;Otherwise, for unknown object types set objectType to equal #COMate_UnknownObjectType. In these cases, this method will return the +;interface pointer directly (as opposed to a COMate object). +;In either case the object should be released as soon as it is no longer required. +;Any HRESULT return value is accessible through the GetLastErrorCode() method. +Procedure.i COMateClass_GetObjectProperty(*this._membersCOMateClass, command$, *hStatement=0, objectType = #VT_DISPATCH) + Protected result.i = #S_OK, retVar.VARIANT, *newObject._membersCOMateClass + If command$ Or *hStatement + If objectType <> #VT_DISPATCH + objectType = #VT_UNKNOWN + EndIf + result = COMateClass_INTERNAL_InvokePlus(*this, #DISPATCH_PROPERTYGET|#DISPATCH_METHOD, objectType, retVar, command$, *hStatement) + If SUCCEEDED(result) + If objectType = #VT_DISPATCH + If retVar\pdispVal + ;We now create a COMate object to house this instance variable. + *newObject = AllocateMemory(SizeOf(_membersCOMateClass)) + If *newObject + *newObject\vTable = ?VTable_COMateClass + *newObject\iDisp = retVar\pdispVal + COMate_gNumObjects+1 + Else + VariantClear_(retVar) ;This will call the Release() method of the COM object. + result = #E_OUTOFMEMORY + EndIf + Else + VariantClear_(retVar) + ;In this case we set an error with extra info. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, #S_FALSE, 0, "The property returned a NULL object!") + CompilerEndIf + result = -1 + EndIf + Else + *newObject = retVar\punkVal + EndIf + Else + VariantClear_(retVar) + EndIf + Else + result = #E_INVALIDARG + EndIf + ;Set any error code. iDispatch errors will alreay have been set. + If result <> -1 + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + EndIf + ProcedureReturn *newObject +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method calls a dispinterface function and returns a double value. +;Any HRESULT return value is accessible through the GetLastErrorCode() method. +Procedure.d COMateClass_GetRealProperty(*this._membersCOMateClass, command$, *hStatement=0) + Protected result.i = #S_OK, retVar.VARIANT, retValue.d + If command$ Or *hStatement + result = COMateClass_INTERNAL_InvokePlus(*this, #DISPATCH_PROPERTYGET|#DISPATCH_METHOD, #VT_R8, retVar, command$, *hStatement) + If SUCCEEDED(result) + retValue = retVar\dblval + EndIf + VariantClear_(retVar) + Else + result = #E_INVALIDARG + EndIf + ;Set any error code. iDispatch errors will alreay have been set. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn retValue +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method calls a dispinterface function and returns a string value. +;Any HRESULT return value is accessible through the GetLastErrorCode() method. +Procedure.s COMateClass_GetStringProperty(*this._membersCOMateClass, command$, *hStatement=0) + Protected result.i = #S_OK, retVar.VARIANT, result$ + If command$ Or *hStatement + result = COMateClass_INTERNAL_InvokePlus(*this, #DISPATCH_PROPERTYGET|#DISPATCH_METHOD, #VT_BSTR, retVar, command$, *hStatement) + If SUCCEEDED(result) And retVar\bstrVal + result$ = PeekS(retVar\bstrVal, -1, #PB_Unicode) + EndIf + VariantClear_(retVar) + Else + result = #E_INVALIDARG + EndIf + ;Set any error code. iDispatch errors will alreay have been set. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn result$ +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method calls a dispinterface function and, if there are no errors, returns a pointer to a new variant which must be +;'freed' by the user with VariantClear_() etc. +;Any HRESULT return value is accessible through the GetLastErrorCode() method. +Procedure.i COMateClass_GetVariantProperty(*this._membersCOMateClass, command$, *hStatement=0) + Protected result.i = #S_OK, *retVar.VARIANT + If command$ Or *hStatement + ;Allocate memory for a new variant. + *retVar = AllocateMemory(SizeOf(VARIANT)) + If *retVar + result = COMateClass_INTERNAL_InvokePlus(*this, #DISPATCH_PROPERTYGET|#DISPATCH_METHOD, #VT_EMPTY, *retVar, command$, *hStatement) + If FAILED(result) + FreeMemory(*retVar) + *retVar = 0 + EndIf + Else + result = #E_OUTOFMEMORY + EndIf + Else + result = #E_INVALIDARG + EndIf + ;Set any error code. iDispatch errors will alreay have been set. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn *retVar +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method calls a dispinterface method where no return value is required. +;Returns a HRESULT value. #S_OK for no errors. +;Errors reported by the methods called by the user will be reported elsewhere (eventually!) +Procedure.i COMateClass_SetProperty(*this._membersCOMateClass, command$, *hStatement=0) + Protected result.i = #S_OK + If command$ Or *hStatement + result = COMateClass_INTERNAL_InvokePlus(*this, #DISPATCH_PROPERTYPUT, #VT_EMPTY, 0, command$, *hStatement) + Else + result = #E_INVALIDARG + EndIf + ;Set any error code. iDispatch errors will alreay have been set. + If result = -1 + result = #S_FALSE + Else + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + EndIf + ProcedureReturn result +EndProcedure +;================================================================================= + + +;================================================================================= +;The following function calls a dispinterface method where no return value is required. +;Returns a HRESULT value. #S_OK for no errors. +;Errors reported by the methods called by the user will be reported elsewhere (eventually!) +Procedure.i COMateClass_SetPropertyRef(*this._membersCOMateClass, command$, *hStatement=0) + Protected result.i = #S_OK + If command$ Or *hStatement + result = COMateClass_INTERNAL_InvokePlus(*this, #DISPATCH_PROPERTYPUTREF, #VT_EMPTY, 0, command$, *hStatement) + Else + result = #E_INVALIDARG + EndIf + ;Set any error code. iDispatch errors will alreay have been set. + If result = -1 + result = #S_FALSE + Else + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + EndIf + ProcedureReturn result +EndProcedure +;================================================================================= + + +CompilerIf Defined(COMATE_NOINCLUDEATL, #PB_Constant)=0 + +;-COMate CLASS - EVENT RELATED METHODS. +;--------------------------------------------------------------------------------- + +;================================================================================= +;The following method attaches an event handler from the user's program to the underlying COM object. (Code based on that written by Freak.) +;Set callback to zero to remove any existing callback. +;Returns a HRESULT value. #S_OK for no errors. +Procedure.i COMateClass_SetEventHandler(*this._membersCOMateClass, eventName$, callback, returnType = #COMate_NORETURN, *riid.IID=0) + Protected result.i = #S_OK + Protected container.IConnectionPointContainer, enum.IEnumConnectionPoints, connection.IConnectionPoint, connIID.IID + Protected dispTypeInfo.ITypeInfo, typeLib.ITypeLib, typeInfo.ITypeInfo + Protected infoCount, index + Protected *sink._COMateEventSink, newSink.IDispatch + If eventName$ = #COMate_CatchAllEvents Or *this\hWnd + If returnType < #COMate_NoReturn Or returnType > #COMate_OtherReturn + returnType = #COMate_NoReturn + EndIf + If eventName$ = #COMate_CatchAllEvents + If returnType <> #COMate_NORETURN + returnType = #COMate_OtherReturn ;No sense in an explicit return value when dealing with any event! + EndIf + ;If their already exists a sink for this object then we just switch the main callback. + If *this\eventSink And callback + *this\eventSink\callback = callback + *this\eventSink\returnType = returnType + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn result ;No error. + ElseIf *this\eventSink = 0 And callback = 0 ;No point proceeding with this. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn result ;No error reported. + EndIf + ElseIf *this\eventSink + If callback And *this\hWnd + SetProp_(*this\hWnd, eventName$+"_COMate", callback) + SetProp_(*this\hWnd, eventName$+"_RETURN_COMate", returnType) + ElseIf *this\hWnd + RemoveProp_(*this\hWnd, eventName$+"_COMate") + RemoveProp_(*this\hWnd, eventName$+"_RETURN_COMate") + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn result + ElseIf callback = 0 ;*this\eventSink will equal 0 as well. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn result + EndIf + ;Only remaining options are for wishing to remove a previously installed sink (requires #COMate_CatchAllEvents) or a completely new sink is to be installed. + result = *this\iDisp\GetTypeInfoCount(@infoCount) + If SUCCEEDED(result) + If InfoCount = 1 + result = *this\iDisp\GetTypeInfo(0, 0, @dispTypeInfo) + If SUCCEEDED(result) + result = dispTypeInfo\GetContainingTypeLib(@typeLib, @index) + If SUCCEEDED(result) + result = *this\iDisp\QueryInterface(?IID_IConnectionPointContainer, @container) + If SUCCEEDED(result) + If *riid.IID = 0 + result = container\EnumConnectionPoints(@enum.IEnumConnectionPoints) + If SUCCEEDED(result) + enum\Reset() + result = enum\Next(1, @connection, #Null) + While result = #S_OK + result = Connection\GetConnectionInterface(@connIID) + If SUCCEEDED(result) ;We have a valid IID for the outgoing interface managed by this connection point. + result = typeLib\GetTypeInfoOfGuid(connIID, @typeInfo) + If SUCCEEDED(result) + enum\Release() + Goto COMateClass_SetEventHandler_L1 + EndIf + EndIf + connection\Release() + result = enum\Next(1, @connection, #Null) + Wend + enum\Release() + EndIf + Else ;The user has specified a connection point interface. + result = container\FindConnectionPoint(*riid, @connection) + If SUCCEEDED(result) + result = Connection\GetConnectionInterface(@connIID) ;May or may not equal the IID pointed to by *riid. + If SUCCEEDED(result) ;We have a valid IID for the outgoing interface managed by this connection point. + result = typeLib\GetTypeInfoOfGuid(*riid, @typeInfo) + If SUCCEEDED(result) +COMateClass_SetEventHandler_L1: + If eventName$ = #COMate_CatchAllEvents And callback = 0 ;Remove existing sink. + ;The Unadvise() method will call Release() on our sink and so we leave all tidying up to this method. + connection\Unadvise(*this\eventSink\cookie) + TypeInfo\Release() + Else ;New sink needs creating. + *sink = AllocateMemory(SizeOf(_COMateEventSink)) + If *sink + *this\eventSink = *sink + With *this\eventSink + \Vtbl = ?VTable_COMateEventSink + \refCount = 1 + \typeInfo = typeInfo + If eventName$ = #COMate_CatchAllEvents + \callback = Callback + \returnType = returnType + ElseIf *this\hWnd + SetProp_(*this\hWnd, eventName$+"_COMate", callback) + SetProp_(*this\hWnd, eventName$+"_RETURN_COMate", returnType) + EndIf + CopyMemory(connIID, @\connIID, SizeOf(IID)) + \parent = *this + EndWith + newSink = *sink + result = connection\Advise(newSink, @*this\eventSink\cookie) ;Calls QueryInterface() on NewSink hence the subsequent Release(). + ;In the case of an error this release will decrement the ref counter to zero and then tidy up! + NewSink\Release() + Else + TypeInfo\Release() + result = #E_OUTOFMEMORY + EndIf + EndIf + EndIf + EndIf + connection\Release() + EndIf + EndIf + container\Release() + EndIf + typeLib\Release() + EndIf + dispTypeInfo\Release() + EndIf + EndIf + EndIf + Else + result = #E_FAIL + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn result +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method, valid only when called from a user's event procedure, retrieves the specified parameter in the form +;of a quad. +Procedure.q COMateClass_GetIntegerEventParam(*this._membersCOMateClass, index) + Protected result.i = #S_OK, var.VARIANT, puArgErr + If *this\eventSink And *this\eventSink\dispParams + If index > 0 And index <= *this\eventSink\dispParams\cArgs+*this\eventSink\dispParams\cNamedArgs + result = DispGetParam_(*this\eventSink\dispParams, index-1, #VT_I8, var, @puArgErr) + Else + result = #E_INVALIDARG + EndIf + Else + result = #E_FAIL + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn var\llval +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method, valid only when called from a user's event procedure, retrieves the specified parameter in the form +;of a COM interface. It does not wrap any returned object into a COMate object. Returns zero if an error. +;The user MUST call Release() on any object returned. +;Leave objectType = #VT_DISPATCH to have an iDispatch interface returned. Any other value will result in an iUnknown interface. +Procedure.i COMateClass_GetObjectEventParam(*this._membersCOMateClass, index, objectType = #VT_DISPATCH) + Protected result.i = #S_OK, var.VARIANT, puArgErr + If *this\eventSink And *this\eventSink\dispParams + If index > 0 And index <= *this\eventSink\dispParams\cArgs+*this\eventSink\dispParams\cNamedArgs + If objectType <> #VT_DISPATCH + objectType = #VT_UNKNOWN + EndIf + result = DispGetParam_(*this\eventSink\dispParams, index-1, objectType, @var, @puArgErr) + Else + result = #E_INVALIDARG + EndIf + Else + result = #E_FAIL + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn var\pDispVal +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method, valid only when called from a user's event procedure, retrieves the specified parameter in the form +;of a double. +Procedure.d COMateClass_GetRealEventParam(*this._membersCOMateClass, index) + Protected result.i = #S_OK, var.VARIANT, puArgErr + If *this\eventSink And *this\eventSink\dispParams + If index > 0 And index <= *this\eventSink\dispParams\cArgs+*this\eventSink\dispParams\cNamedArgs + result = DispGetParam_(*this\eventSink\dispParams, index-1, #VT_R8, var, @puArgErr) + Else + result = #E_INVALIDARG + EndIf + Else + result = #E_FAIL + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn var\dblVal +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method, valid only when called from a user's event procedure, retrieves the specified parameter in the form +;of a string. +Procedure.s COMateClass_GetStringEventParam(*this._membersCOMateClass, index) + Protected result.i = #S_OK, var.VARIANT, puArgErr, text$ + If *this\eventSink And *this\eventSink\dispParams + If index > 0 And index <= *this\eventSink\dispParams\cArgs+*this\eventSink\dispParams\cNamedArgs + result = DispGetParam_(*this\eventSink\dispParams, index-1, #VT_BSTR, var, @puArgErr) + If var\bstrVal + text$ = PeekS(var\bstrVal, -1, #PB_Unicode) + SysFreeString_(var\bstrVal) + EndIf + Else + result = #E_INVALIDARG + EndIf + Else + result = #E_FAIL + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result) + CompilerEndIf + ProcedureReturn text$ +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method, valid only when called from a user's event procedure, returns 0 if the specified parameter was +;not passed by reference. +;Otherwise, it returns the variant #VT_... type of the underlying parameter and it places the address of the underlying +;parameter into the *ptrParameter parameter (if non-zero). This allows the client application to alter the value of the parameter +;as appropriate. +;For even more flexibility, you can obtain a pointer to the actual variant containing the parameter as supplied by the ActiveX control. +Procedure.i COMateClass_IsEventParamPassedByRef(*this._membersCOMateClass, index, *ptrParameter.INTEGER=0, *ptrVariant.INTEGER=0) + Protected result.i = #S_OK, *var.VARIANT, *ptr.INTEGER, numArgs + If *this\eventSink And *this\eventSink\dispParams + numArgs = *this\eventSink\dispParams\cArgs+*this\eventSink\dispParams\cNamedArgs + If index > 0 And index <= numArgs + *var = *this\eventSink\dispParams\rgvarg + (numArgs-index)*SizeOf(VARIANT) + If *var\vt&#VT_BYREF + result = *var\vt&~#VT_BYREF + If *ptrParameter + *ptrParameter\i = *var\pllval + EndIf + If *ptrVariant + *ptrVariant\i = *var + EndIf + EndIf + Else + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, #E_INVALIDARG) + CompilerEndIf + EndIf + Else + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, #E_FAIL) + CompilerEndIf + EndIf + ProcedureReturn result +EndProcedure +;================================================================================= + +CompilerEndIf + + +;///////////////////////////////////////////////////////////////////////////////// +;The following function is called by the COMatePLUS_CompileSubobjectInvokation() function when extracting method arguments and only when the final +;option is a numeric argument. +;Returns #True if a valid variant numeric type is found and also places the relevant value within the given variant. +Procedure.i COMate_INTERNAL_CheckNumeric(arg$, *var.VARIANT) + Protected result.i = #True, i, blnPoint, length, *ptr.CHARACTER + Protected val.q, byte.b, word.w, long.l + length = Len(arg$) + *ptr = @arg$ + For i = 1 To length + If *ptr\c = '-' Or *ptr\c = '+' + If i > 1 + result = 0 + Break + EndIf + ElseIf *ptr\c = '.' And blnPoint = #False + blnPoint = #True + ElseIf *ptr\c < '0' Or *ptr\c > '9' + result = 0 + Break + EndIf + *ptr+SizeOf(CHARACTER) + Next + If result + If blnPoint ;Decimal. + *var\vt = #VT_R8 + *var\dblVal = ValD(arg$) + Else ;Some kind of integer. + val = Val(arg$) + If val = 0 ;Shove this into a signed 'long'. + *var\vt = #VT_I4 + *var\lVal = 0 + Else + ;Check if the value will fit into a signed-byte or a signed-word or a signed-long or a signed-quad. + byte = val + If byte = val ;Signed byte. + *var\vt = #VT_I1 + *var\cVal = val + Else + word = val + If word = val ;Signed word. + *var\vt = #VT_I2 + *var\iVal = val + Else + long = val + If long = val ;Signed long. + *var\vt = #VT_I4 + *var\lVal = val + Else ;Quad. + *var\vt = #VT_I8 + *var\llVal = val + EndIf + EndIf + EndIf + EndIf + EndIf + EndIf + ProcedureReturn result +EndProcedure +;///////////////////////////////////////////////////////////////////////////////// + + +;///////////////////////////////////////////////////////////////////////////////// +;The following function is called by the COMatePLUS_CompileSubobjectInvokation() function when extracting method arguments and only for non-empty strings. +;Quoted strings (beginning with ') can contain escaped sequences of the form $xxxx where xxxx represent a hex number. +;Together $xxxx represents a single character code; e.g. an Ascii code. E.g. $0024 would be replaced by a $ character and +;$0027 would be replaced by a ' character. +;Adjusts the string in-place. +Procedure COMate_INTERNAL_EscapeString(ptrText) + Protected *source.CHARACTER, *destination.CHARACTER, blnEscape, value, t1, pow, i + *source.CHARACTER = ptrText + *destination = *source + While *source\c + If *source\c = 36 + ;Is this the beginning of an escape sequence? + blnEscape = #True + t1 = *source + value = 0 + pow = 4096 ;16^3. + For i = 1 To 4 + *source + SizeOf(CHARACTER) + If *source\c = 0 ;Null terminator. + Break 2 + ElseIf *source\c >= '0' And *source\c <= '9' + value + (*source\c-'0')*pow + ElseIf *source\c >= 'A' And *source\c <= 'F' + value + (*source\c-'A'+10)*pow + ElseIf *source\c >= 'a' And *source\c <= 'f' + value + (*source\c-'a'+10)*pow + Else + blnEscape = #False + Break + EndIf + pow>>4 + Next + If blnEscape ;We have an escape sequence. + *destination\c = value&$ff : *destination + SizeOf(CHARACTER) + *source + SizeOf(CHARACTER) + Else + *source = t1 + Goto COMate_labelEscape1 + EndIf + Else +COMate_labelEscape1: + *destination\c = *source\c + *destination + SizeOf(CHARACTER) + *source + SizeOf(CHARACTER) + EndIf + Wend + *destination\c = 0 ;Null termminator. +EndProcedure +;///////////////////////////////////////////////////////////////////////////////// + + +;///////////////////////////////////////////////////////////////////////////////// +;The following function is called (possibly more than once) by the COMateClass_INTERNAL_InvokePlus as we drill down through +;subobject method calls etc. This performs the task of calling the dispinterface methods. +;Returns a HRESULT value; #S_OK for no errors. +Procedure.i COMateClass_INTERNAL_InvokeiDispatch(*this._membersCOMateClass, invokeType, returnType, *ret.VARIANT, iDisp.iDispatch, subObjectIndex, *statement._COMatePLUSStatement) + Protected result.i = #S_OK + Protected dispID, dp.DISPPARAMS, dispIDNamed, excep.EXCEPINFO2, uiArgErr + ;First task is to retrieve the dispID corresponding to the method/property. + result = iDisp\GetIDsOfNames(?IID_NULL, @*statement\methodName[subObjectIndex], 1, #LOCALE_USER_DEFAULT, @dispID) + If SUCCEEDED(result) + ;Now prepare to call the method/property. + dispidNamed = #DISPID_PROPERTYPUT + If *statement\numArgs[subObjectIndex] + dp\rgvarg = *statement\ptrVarArgs[subObjectIndex] + (#COMate_MAXNUMVARIANTARGS - *statement\numArgs[subObjectIndex])*SizeOf(VARIANT) + EndIf + dp\cargs = *statement\numArgs[subObjectIndex] + If invokeType & (#DISPATCH_PROPERTYPUT | #DISPATCH_PROPERTYPUTREF) + dp\cNamedArgs = 1 + dp\rgdispidNamedArgs = @dispidNamed + EndIf + ;Call the method/property. + result = iDisp\Invoke(dispID, ?IID_NULL, #LOCALE_USER_DEFAULT, invokeType, dp, *ret, excep, @uiArgErr) + If result = #DISP_E_EXCEPTION + ;Has the automation server deferred from filling in the EXCEPINFO2 structure? + If excep\pfnDeferredFillIn + excep\pfnDeferredFillIn(excep) + EndIf + If excep\bstrSource + SysFreeString_(excep\bstrSource) + EndIf + If excep\bstrDescription + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result, #True, PeekS(excep\bstrDescription, -1, #PB_Unicode)) + CompilerEndIf + SysFreeString_(excep\bstrDescription) + Else + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, result, #True) + CompilerEndIf + EndIf + If excep\bstrHelpFile + SysFreeString_(excep\bstrHelpFile) + EndIf + EndIf + EndIf + ProcedureReturn result +EndProcedure +;///////////////////////////////////////////////////////////////////////////////// + + +;///////////////////////////////////////////////////////////////////////////////// +;The following function is called by all methods which need to invoke a COM method through iDispatch etc. +;It drills down through all the sub-objects of a method call as appropriate. +;Returns a HRESULT value; #S_OK for no errors. +Procedure.i COMateClass_INTERNAL_InvokePlus(*this._membersCOMateClass, invokeType, returnType, *ret.VARIANT, command$, *hStatement._COMatePLUSStatement) + Protected result.i = #S_OK, *statement._COMatePLUSStatement, subObjectIndex + Protected iDisp.iDispatch, var.VARIANT + ;First job is to prepare a statement if one has not been provided by the developer. + If *hStatement + *statement = *hStatement + Else + result = COMate_INTERNAL_PrepareStatement(command$, @*statement) + EndIf + If *statement + VariantInit_(var) + iDisp = *this\iDisp + iDisp\AddRef() ;This seemingly extraneous AddRef() will be balanced (released) in the following loop or the code following the loop. + For subObjectIndex = 1 To *statement\numSubObjects-1 + result = COMateClass_INTERNAL_InvokeiDispatch(*this, #DISPATCH_METHOD|#DISPATCH_PROPERTYGET, #VT_DISPATCH, var, iDisp, subObjectIndex, *statement) + iDisp\Release() + iDisp = var\pdispVal + If FAILED(result) Or iDisp = 0 + Break + EndIf + VariantInit_(var) + Next + If SUCCEEDED(result) + If iDisp + result = COMateClass_INTERNAL_InvokeiDispatch(*this, invokeType, returnType, *ret, iDisp, *statement\numSubObjects, *statement) + iDisp\Release() + Else + ;In this case we set an error with extra info. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this, #S_FALSE, 0, "The '" + PeekS(*statement\methodName[subObjectIndex], -1, #PB_Unicode) + "' property returned a NULL object!") + CompilerEndIf + result = -1 ;This will ensure that the COMateClass_INTERNAL_SetError() does not reset the error. + EndIf + If SUCCEEDED(result) + ;Sort out any return. + If *ret And *ret\vt <> returnType And returnType <> #VT_EMPTY + result = VariantChangeType_(*ret, *ret, 16, returnType) + EndIf + EndIf + EndIf + ;Tidy up. + If *hStatement = 0 + COMate_INTERNAL_FreeStatementHandle(*statement) + EndIf + EndIf + ProcedureReturn result +EndProcedure +;///////////////////////////////////////////////////////////////////////////////// + + +;/////////////////////////////////////////////////////////////////////////////////////////// +;iDispatch errors will already have been processed. +Procedure COMateClass_INTERNAL_SetError(*this._membersCOMateClass, result, blnAllowDispError = 0, dispError$="") + Protected *error._COMateThreadErrors, Array.i, winError, len, *buffer + If COMate_gErrorTLS = 0 Or COMate_gErrorTLS = -1 + ;Create a new TLS index to hold error information. + COMate_gErrorTLS = TlsAlloc_() + EndIf + If COMate_gErrorTLS = -1 Or result = -1 Or (result = #DISP_E_EXCEPTION And blnAllowDispError = 0) + ProcedureReturn + EndIf + ;Is there a TLS entry for this thread. + *error = TlsGetValue_(COMate_gErrorTLS) + If *error = 0 ;No existing entry. + ;Attempt to allocate memory for a TLS entry for this thread. + *error = AllocateMemory(SizeOf(_COMateThreadErrors)) + If *error + If TlsSetValue_(COMate_gErrorTLS, *error) + ;Need to extend the memory if already allocated for the *COMate_gPtrThreadArray array so that the error memory can be freed later on. + Array = ReAllocateMemory(COMate_gPtrThreadArray, (COMate_gNumThreadElements+1)*SizeOf(Array)) + If Array + COMate_gPtrThreadArray = Array + PokeI(COMate_gPtrThreadArray + COMate_gNumThreadElements*SizeOf(Array), *error) + COMate_gNumThreadElements+1 + Else + TlsSetValue_(COMate_gErrorTLS, 0) + FreeMemory(*error) + *error = 0 + EndIf + Else + FreeMemory(*error) + *error = 0 + EndIf + EndIf + EndIf + If *error + *error\lastErrorCode = result + Select result + Case #S_OK + *error\lastError$ = "Okay." + Case #S_FALSE + If dispError$ + *error\lastError$ = "The operation completed, but was only partially successful. (" + dispError$ + ")" + Else + *error\lastError$ = "The operation completed, but was only partially successful." + EndIf + Case #E_FAIL + *error\lastError$ = "Unspecified error." + Case #E_INVALIDARG + *error\lastError$ = "One or more arguments are invalid. Possibly a numerical overflow or too many nested objects, -if so, try splitting your method call into two or more subcalls." + Case #E_NOINTERFACE + *error\lastError$ = "Method is not implemented." + Case #E_OUTOFMEMORY + *error\lastError$ = "Problem allocating memory." + #CRLF$ + #CRLF$ + "(Possibly too many method arguments. Each method/property is limited by COMatePLUS to a maximum of " + Str(#COMate_MAXNUMVARIANTARGS) + " arguments.)" + Case #E_UNEXPECTED + *error\lastError$ = "An unexpected error." + Case #E_POINTER + *error\lastError$ = "An invalid pointer was supplied." + Case #E_NOTIMPL + *error\lastError$ = "Not implemented. In the case of attaching an event handler to a COM object, this could signify that the object does not provide any type information." + Case #CO_E_CLASSSTRING, #REGDB_E_CLASSNOTREG + *error\lastError$ = "Invalid progID/CLSID. Check your spelling of the programmatic identifier. Also check that the component / ActiveX control has been registered." + Case #CO_E_SERVER_EXEC_FAILURE + *error\lastError$ = "Server execution failed. Usually caused by an 'out of process server' timing out when asked to create an instance of a 'class factory'." + Case #DISP_E_TYPEMISMATCH + *error\lastError$ = "Type mismatch in the method parameters." + Case #TYPE_E_ELEMENTNOTFOUND + *error\lastError$ = "No type description was found in the library with the specified GUID whilst trying to create an event handler." + Case #CONNECT_E_ADVISELIMIT + *error\lastError$ = "Unable to set event handler because the connection point has already reached its limit of connections." + Case #CLASS_E_NOAGGREGATION + *error\lastError$ = "Class does not support aggregation (or class object is remote)." + Case #DISP_E_OVERFLOW + *error\lastError$ = "Overflow error whilst converting between types." + Case #DISP_E_UNKNOWNNAME + *error\lastError$ = "Method/property not supported by this object." + Case #DISP_E_BADPARAMCOUNT + *error\lastError$ = "Invalid number of method/property parameters." + Case #DISP_E_BADVARTYPE + *error\lastError$ = "A method/property parameter is not a valid (variant) type." + Case #DISP_E_MEMBERNOTFOUND + *error\lastError$ = "Member not found. (Check that you have not omitted any optional parameters and are not trying to set a read-only property etc.)" + Case #DISP_E_NOTACOLLECTION + *error\lastError$ = "Does not support a collection." + Case #E_ACCESSDENIED + *error\lastError$ = "A 'general' access denied error." + Case #RPC_E_WRONG_THREAD + *error\lastError$ = "The application called upon an interface that was marshalled for a different thread." + Case #DISP_E_EXCEPTION + *error\lastError$ = dispError$ + If *error\lastError$ = "" + *error\lastError$ = "An exception occurred during the execution of this method/property." + EndIf + Default + ;Check for a WIN32 facility code. + If *error\lastErrorCode & $7FFF0000 = $70000 + winError = *error\lastErrorCode&$FFFF + len = FormatMessage_(#FORMAT_MESSAGE_ALLOCATE_BUFFER|#FORMAT_MESSAGE_FROM_SYSTEM, 0, winError, 0, @*Buffer, 0, 0) + If len + *error\lastError$ = "(FACILITY_WIN32 error " + Str(winError) + ") " + PeekS(*Buffer, len) + LocalFree_(*Buffer) + Else + *error\lastError$ = "(FACILITY_WIN32 error " + Str(winError) + ") Unable to retrieve error description from system!" + EndIf + Else + *error\lastError$ = "Unknown error. (Code : Hex " + Hex(*error\lastErrorCode, #PB_Long) + "). Please report this error code to the author at 'enquiries@nxsoftware.com'" + EndIf + EndSelect + EndIf +EndProcedure +;/////////////////////////////////////////////////////////////////////////////////////////// + + +CompilerIf Defined(COMATE_NOINCLUDEATL, #PB_Constant)=0 +;-OUTGOING 'SINK' INTERFACE METHODS. +;------------------------------------------------------------------------ + +;================================================================================= +;The QueryInterface() method of our COMate sink objects. +Procedure.i COMateSinkClass_QueryInterface(*this._COMateEventSink, *IID.IID, *Object.INTEGER) + If CompareMemory(*IID, ?IID_IUnknown, SizeOf(IID)) Or CompareMemory(*IID, ?IID_IDispatch, SizeOf(IID)) Or CompareMemory(*IID, @*this\connIID, SizeOf(IID)) + *Object\i = *this + *this\refCount + 1 + ProcedureReturn #S_OK + Else + *Object\i = 0 + ProcedureReturn #E_NOINTERFACE + EndIf +EndProcedure +;================================================================================= + + +;================================================================================= +;The AddRef() method of our COMate sink objects. +Procedure.i COMateSinkClass_AddRef(*this._COMateEventSink) + *this\refCount + 1 + ProcedureReturn *this\refCount +EndProcedure +;================================================================================= + + +;================================================================================= +;The Release() method of our COMate sink objects. +Procedure.i COMateSinkClass_Release(*this._COMateEventSink) + *this\refCount - 1 + If *this\refCount = 0 + If *this\parent + ;Release all event related window properties added to the ActiveX container. + If IsWindow_(*this\parent\hWnd) + EnumPropsEx_(*this\parent\hWnd, @COMate_DelSinkPropsCallback(),#Null) + EndIf + *this\parent\eventSink = 0 + EndIf + *this\typeInfo\Release() + FreeMemory(*this) + ProcedureReturn 0 + Else + ProcedureReturn *this\refCount + EndIf +EndProcedure +;================================================================================= + + +;================================================================================= +;The next 3 methods of the COMate sink interface are possibly not required, but ... +Procedure.i COMateSinkClass_GetTypeInfoCount(*this._COMateEventSink, *pctinfo.INTEGER) + *pctinfo\i = 1 + ProcedureReturn #S_OK +EndProcedure + +Procedure.i COMateSinkClass_GetTypeInfo(*this._COMateEventSink, iTInfo, lcid, *ppTInfo.INTEGER) + *ppTInfo\i = *this\typeInfo + *this\typeInfo\AddRef() + ProcedureReturn #S_OK +EndProcedure + +Procedure.i COMateSinkClass_GetIDsOfNames(*this._COMateEventSink, *riid, *rgszNames, *cNames, lcid, *DispID) + ProcedureReturn DispGetIDsOfNames_(*this\typeInfo, *rgszNames, *cNames, *DispID) +EndProcedure +;================================================================================= + + +;================================================================================= +;The Invoke() method of our COMate sink objects. +;This is where we call the user's event procedure. +Procedure.i COMateSinkClass_Invoke(*this._COMateEventSink, dispid, *riid, lcid, wflags.w, *Params.DISPPARAMS, *Result.VARIANT, *pExept, *ArgErr) + Protected result.i = #S_OK, bstrName.i, nameCount, tempParams, eventName$, returnType, address + Protected callbackNoReturn.COMate_EventCallback_NORETURN, callbackIntegerReturn.COMate_EventCallback_INTEGERRETURN, callbackRealReturn.COMate_EventCallback_REALRETURN, callbackStringReturn.COMate_EventCallback_STRINGRETURN, callbackUnknownReturn.COMate_EventCallback_UNKNOWNRETURN + Protected intRet.q, realRet.d, stringRet$ + result = *this\TypeInfo\GetNames(dispid, @bstrName, 1, @nameCount) + If SUCCEEDED(result) + If bstrName + tempParams = *this\dispParams + *this\dispParams = *Params + eventName$ = PeekS(bstrName, -1, #PB_Unicode) + SysFreeString_(bstrName) + ;Call the 'global' #COMate_CatchAllEvents handler if defined. + If *this\callback + If *this\returnType = #COMate_OtherReturn + callbackUnknownReturn = *this\callback + callbackUnknownReturn(*this\parent, eventName$, *Params\cArgs + *Params\cNamedArgs, *Result) + Else + *this\callback(*this\parent, eventName$, *Params\cArgs + *Params\cNamedArgs) + EndIf + EndIf + ;Call any individual handler attached to this event. We need to take into account the return type. + If *this\parent\hWnd + address = GetProp_(*this\parent\hWnd, eventName$ + "_COMate") + If address + returnType = GetProp_(*this\parent\hWnd, eventName$ + "_RETURN_COMate") + Select returnType + Case #COMate_NoReturn + callbackNoReturn = address + callbackNoReturn(*this\parent, eventName$, *Params\cArgs + *Params\cNamedArgs) + Case #COMate_IntegerReturn + callbackIntegerReturn = address + intRet = callbackIntegerReturn(*this\parent, eventName$, *Params\cArgs + *Params\cNamedArgs) + If *Result + *Result\vt = #VT_I8 + *Result\llVal = intRet + EndIf + Case #COMate_RealReturn + callbackRealReturn = address + realRet = callbackRealReturn(*this\parent, eventName$, *Params\cArgs + *Params\cNamedArgs) + If *Result + *Result\vt = #VT_R8 + *Result\dblVal = realRet + EndIf + Case #COMate_StringReturn + callbackStringReturn = address + stringRet$ = callbackStringReturn(*this\parent, eventName$, *Params\cArgs + *Params\cNamedArgs) + If *Result + *Result\vt = #VT_BSTR + *Result\bstrVal = COMate_MakeBSTR(stringRet$) + EndIf + Case #COMate_OtherReturn + callbackUnknownReturn = address + callbackUnknownReturn(*this\parent, eventName$, *Params\cArgs + *Params\cNamedArgs, *Result) + EndSelect + EndIf + EndIf + *this\dispParams = tempParams + Else + result = #E_OUTOFMEMORY + EndIf + EndIf + ProcedureReturn result +EndProcedure +;================================================================================= + + +;================================================================================= +;The following callback function is called by windows as a result of the EnumPropsEx_() function +;issued when an outgoing sink object is destroyed. +;We use this to delete the properties we have created. +Procedure.i COMate_DelSinkPropsCallback(hWnd, lpszString, hData,dwData) + Protected text$ + If lpszString>>16<>0 ;Confirms that this parameter points to a string and is not merely an atom. + text$ = PeekS(lpszString) + If Right(PeekS(lpszString),7)="_COMate" + RemoveProp_(hWnd, lpszString) + EndIf + EndIf +ProcedureReturn 1 +EndProcedure +;================================================================================= + +CompilerEndIf + + +;-STATEMENT FUNCTIONS. +;---------------------------------------------- + +;================================================================================= +;The following function compiles the given command string and if successful, returns a statement handle. +;Returns zero otherwise. +Procedure.i COMate_PrepareStatement(command$) + Protected errorCode = #S_OK, *hStatement._COMatePLUSStatement + errorCode = COMate_INTERNAL_PrepareStatement(command$, @*hStatement) + ;Set any error code. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(0, errorCode) + CompilerEndIf + ProcedureReturn *hStatement +EndProcedure +;================================================================================= + + +;================================================================================= +;Returns, if successful, a direct pointer to the appropriate variant structure. This address will not change for the life of the statement +;and thus need only be retrieved once. +;Index is 1-based. +Procedure.i COMate_GetStatementParameter(*hStatement._COMatePLUSStatement, index) + Protected errorCode = #E_INVALIDARG, result, i, total + If index > 0 + ;Track down which sub-object + For i = 1 To *hStatement\numSubObjects + total + *hStatement\numArgs[i] + If index <= total + ;Adjust the index to reflect the underlying sub-object's number of parameters. + index = *hStatement\numArgs[i] - total + index + ;Locate the relevant variant argument. + result= *hStatement\ptrVarArgs[i] + (#COMate_MAXNUMVARIANTARGS - index)*SizeOf(VARIANT) + errorCode = #S_OK + Break + EndIf + Next + EndIf + ;Set any error code. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(0, errorCode) + CompilerEndIf + ProcedureReturn result +EndProcedure +;================================================================================= + + +;================================================================================= +;The following function frees the specified statement. +Procedure COMate_FreeStatementHandle(*hStatement._COMatePLUSStatement) + COMate_INTERNAL_FreeStatementHandle(*hStatement) + ;Set any error code. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(0, #S_OK) + CompilerEndIf +EndProcedure +;================================================================================= + + +;-INTERNAL FUNCTIONS. +;------------------------------------------ + +;================================================================================= +;The following function frees the specified statement but does not set any error. +Procedure COMate_INTERNAL_FreeStatementHandle(*hStatement._COMatePLUSStatement) + Protected i, j, *varArg.VARIANT + For i = 1 To *hStatement\numSubObjects + ;First free any method BSTR. + If *hStatement\methodName[i] + SysFreeString_(*hStatement\methodName[i]) + EndIf + ;Now the variant array. + If *hStatement\ptrVarArgs[i] + *varArg = *hStatement\ptrVarArgs[i] + (#COMate_MAXNUMVARIANTARGS - 1) * SizeOf(VARIANT) + For j = 1 To *hStatement\numArgs[i] + VariantClear_(*varArg) + *varArg - SizeOf(VARIANT) + Next + FreeMemory(*hStatement\ptrVarArgs[i]) + EndIf + Next + FreeMemory(*hStatement) +EndProcedure +;================================================================================= + + +;================================================================================= +;The following internal function compiles the given command string and if successful, places a statement handle into the buffer +;pointed to by *ptrStatement. +;Returns a HRESULT but does NOT set any error. +Procedure.i COMate_INTERNAL_PrepareStatement(command$, *ptrStatement.INTEGER) + Protected errorCode = #S_OK, *hStatement._COMatePLUSStatement + Protected Dim parse._COMateParse(#COMate_MAXNUMSUBOBJECTS), i, subObject + If command$ + ;Allocate memory for a statement handle. + *hStatement = AllocateMemory(SizeOf(_COMatePLUSStatement)) + If *hStatement + ;Tokenise the command string. + *hStatement\numSubObjects = COMatePLUS_TokeniseCommand(command$, "(),\'= ", parse()) + If *hStatement\numSubObjects + For subObject = 1 To *hStatement\numSubObjects + ;We need to parse/compile the tokenised command corresponding to each individual sub-object. + errorCode = COMatePLUS_CompileSubobjectInvokation(*hStatement, subObject, parse()) + If errorCode <> #S_OK + COMate_FreeStatementHandle(*hStatement) + Break + EndIf + Next + If errorCode = #S_OK + *ptrStatement\i = *hStatement + EndIf + Else + FreeMemory(*hStatement) + errorCode = #E_INVALIDARG + EndIf + Else + errorCode = #E_OUTOFMEMORY + EndIf + Else + errorCode = #E_INVALIDARG + EndIf + ProcedureReturn errorCode +EndProcedure +;================================================================================= + + +;/////////////////////////////////////////////////////////////////////////////////////////// +;The following function tokenises the given command string. +;Submethod calls (+ associated parameters) are placed into the parse array; 1 element per subobject. +;This is very optimised by avoiding string functions as far as is possible; instead using multiple pointers etc. +;Returns zero if the line cannot be parsed else a count of the number of method calls. +;Error checking is included but is supplemented later on. +Procedure.i COMatePLUS_TokeniseCommand(command$, separator$, Array parse._COMateParse(1)) + Protected length, methodCount=1, numEquals, t1, i, lenSeparator + Protected *command.CHARACTER, *buffer.CHARACTER, buffer, *ptrString.STRING, *ptrSeparator.CHARACTER, charPos = 1 + length=Len(command$) + If length + buffer = AllocateMemory((length+1)*SizeOf(CHARACTER)) + If buffer + lenSeparator = Len(separator$) + *ptrString = @buffer ;Speedy (pointer) access to the contents in the form of a string. + *buffer = buffer + parse(methodCount)\numberoftokens=0 + *command = @command$ + Repeat + ;Search the separator string looking for this character. + *ptrSeparator = @separator$ + t1 = #False + For i = 0 To lenSeparator-1 + If *ptrSeparator\c = *command\c + t1 = #True + Break + EndIf + *ptrSeparator + SizeOf(CHARACTER) + Next + If t1 + If *buffer <> buffer + parse(methodCount)\tokens$[parse(methodCount)\numberoftokens]=*ptrString\s + parse(methodCount)\numberoftokens+1 + *buffer = buffer : *buffer\c = 0 + ElseIf *command\c = 39 ;Open quote, buffer empty. + *buffer\c = *command\c : *buffer + SizeOf(CHARACTER) + ;Find closing quote. + t1 = #False ;Boolean flag to indicate a closing quote. + While charPos < length + charPos + 1 + *command + SizeOf(character) + *buffer\c = *command\c : *buffer + SizeOf(CHARACTER) + If *command\c = 39 + t1 = #True + *buffer\c = 0 ;Null. + Break + EndIf + Wend + If t1 = #False ;No closing quote. + methodCount = 0 + Break + EndIf + parse(methodCount)\tokens$[parse(methodCount)\numberoftokens]=*ptrString\s + parse(methodCount)\numberoftokens+1 + charPos+1 : *command + SizeOf(CHARACTER) + *buffer = buffer : *buffer\c = 0 + ElseIf *command\c <> 32 ;Buffer empty. + If *command\c = 40 ;"(". + parse(methodCount)\numOpenBrackets + 1 + ElseIf *command\c = 41 ;")". + If parse(methodCount)\numOpenBrackets + parse(methodCount)\numCloseBrackets + 1 + Else + methodCount = 0 + Break + EndIf + ElseIf *command\c = 61 ;"=", buffer empty. + numEquals+1 ;Only allow 1 equals and then only for setting properties. + If numEquals > 1 + methodCount = 0 + Break + EndIf + EndIf + If *command\c = 92 ;"\". + If methodCount < #COMate_MAXNUMSUBOBJECTS And parse(methodCount)\numOpenBrackets = parse(methodCount)\numCloseBrackets And parse(methodCount)\numOpenBrackets <=1 And parse(methodCount)\numberoftokens And numEquals = 0 + methodCount+1 + parse(methodCount)\numberoftokens=0 + parse(methodCount)\numOpenBrackets = 0 + parse(methodCount)\numCloseBrackets = 0 + charPos+1 + *command + SizeOf(CHARACTER) + *buffer = buffer : *buffer\c = 0 ;Null. + Else + methodCount = 0 + Break + EndIf + Else + *buffer\c = *command\c : *buffer + SizeOf(CHARACTER) : *buffer\c = 0 + parse(methodCount)\tokens$[parse(methodCount)\numberoftokens]=*ptrString\s + parse(methodCount)\numberoftokens+1 + charPos+1 + *command + SizeOf(CHARACTER) + *buffer = buffer : *buffer\c = 0 ;Null. + EndIf + Else + charPos+1 + *command + SizeOf(CHARACTER) + *buffer = buffer : *buffer\c = 0 ;Null. + EndIf + ElseIf charPos = length + *buffer\c = *command\c : *buffer + SizeOf(CHARACTER) + *buffer\c = 0 ;Null. + parse(methodCount)\tokens$[parse(methodCount)\numberoftokens]=*ptrString\s + parse(methodCount)\numberoftokens+1 + charPos + 1 + Else + *buffer\c = *command\c : *buffer + SizeOf(CHARACTER) : *buffer\c = 0 ;Null. + *command+SizeOf(character) + charPos + 1 + EndIf + Until charPos > length Or parse(methodCount)\numberOfTokens = #COMate_MAXNUMSYMBOLSINALINE + FreeMemory(buffer) + EndIf + EndIf + If methodCount And (parse(methodCount)\numOpenBrackets <> parse(methodCount)\numCloseBrackets Or parse(methodCount)\numOpenBrackets > 1 Or parse(methodCount)\numberoftokens=0) + methodCount = 0 ;Error. + EndIf + ProcedureReturn methodCount +EndProcedure +;/////////////////////////////////////////////////////////////////////////////////////////// + + +;/////////////////////////////////////////////////////////////////////////////////////////// +;The following function compiles the tokenised command corresponding to a sub-object invokation within a command string. +;Returns a HRESULT. +Procedure.i COMatePLUS_CompileSubobjectInvokation(*hStatement._COMatePLUSStatement, subObjectIndex, Array parse._COMateParse(1)) + Protected result = #S_OK, i, *varArg.VARIANT + Protected parseIndex, currentArg$, blnInsideParanthesis, lastArgType, blnByRef, t1$, vt, *cObject._membersCOMateClass, iDispatch.IDISPATCH + ;Allocate memory for a variant array to hold the arguments. + *hStatement\ptrVarArgs[subObjectIndex] = AllocateMemory(#COMate_MAXNUMVARIANTARGS*SizeOf(VARIANT)) + If *hStatement\ptrVarArgs[subObjectIndex] + ;Set *varArg to point at the last variant in the variant array which is to hold the first parameter, + *varArg = *hStatement\ptrVarArgs[subObjectIndex] + (#COMate_MAXNUMVARIANTARGS - 1) * SizeOf(VARIANT) + While parseIndex < parse(subObjectIndex)\numberOfTokens + currentArg$ = parse(subObjectIndex)\tokens$[parseIndex] + Select currentArg$ + Case "(" + If parseIndex<>1 + result = #E_INVALIDARG + Break + EndIf + blnInsideParanthesis = #True + lastArgType = #COMate_OpenParanthesis + Case ")" + If lastArgType = #COMate_OpenParanthesis Or lastArgType = #COMate_Operand + lastArgType = #COMate_CloseParanthesis + blnInsideParanthesis = #False + Else + result = #E_INVALIDARG + Break + EndIf + Case "=" + If (lastArgType = #COMate_CloseParanthesis Or lastArgType = #COMate_Method) + lastArgType = #COMate_Operator + Else + result = #E_INVALIDARG + Break + EndIf + Case "," + If blnInsideParanthesis And lastArgType = #COMate_Operand + lastArgType = #COMate_Operator + Else + result = #E_INVALIDARG + Break + EndIf + Default ;Method or the beginning of an operand. + If parseIndex = 0 + lastArgType = #COMate_Method + *hStatement\methodName[subObjectIndex] = COMate_MakeBSTR(currentArg$) + If *hStatement\methodName[subObjectIndex] = 0 + result = #E_OUTOFMEMORY + Break + EndIf + ElseIf (lastArgType = #COMate_OpenParanthesis) Or (lastArgType = #COMate_Operator);Cannot have 2 operands together. + If *varArg < *hStatement\ptrVarArgs[subObjectIndex] + result = #E_OUTOFMEMORY + Break + EndIf + blnByRef = #False + lastArgType = #COMate_Operand + ;We must add the operand to the variant array. + ;First task is to determine the parameter type. We first examine the operand and decide on the most likely variant format, creating + ;a variant argument as appropriate. We then see if the user has supplied a 'type modifier', in which case we use VariantChangeType_() etc. + *varArg\vt = #VT_BSTR ;Default. + t1$ = LCase(currentArg$) + If t1$ = "#nullstring" + currentArg$ = "" + EndIf + If Left(currentArg$,1) = "'" Or currentArg$ = "";BSTR + currentArg$ = Mid(currentArg$, 2, Len(currentArg$)-2) + ;We parse the string looking for 'escape' sequences. + If currentArg$ + COMate_INTERNAL_EscapeString(@currentArg$) + EndIf + Else + Select t1$ + Case "#false" + *varArg\vt = #VT_BOOL + *varArg\boolVal = #VARIANT_FALSE + Case "#true" + *varArg\vt = #VT_BOOL + *varArg\boolVal = #VARIANT_TRUE + Case "#empty", "#optional", "#opt" ;Used for optional parameters. + *varArg\vt = #VT_ERROR + *varArg\scode = #DISP_E_PARAMNOTFOUND + Case "#void" + If SizeOf(result) = 4 + *varArg\vt = #VT_I4 + *varArg\lval = 0 + Else + *varArg\vt = #VT_I8 + *varArg\llval = 0 + EndIf + Default ;Here we check for numeric types. + If COMate_INTERNAL_CheckNumeric(currentArg$, *varArg) = 0 + result = #E_INVALIDARG ;No other type of valid operand. + Break + EndIf + EndSelect + EndIf + If result = #S_OK And *varArg\vt = #VT_BSTR + *varArg\bstrVal = COMate_MakeBSTR(currentArg$) + If *varArg\bstrVal = 0 + result = #E_OUTOFMEMORY + Break + EndIf + EndIf + If parseIndex < parse(subObjectIndex)\numberOfTokens-1 And LCase(parse(subObjectIndex)\tokens$[parseIndex+1]) = "byref" + blnByRef = #True + parseIndex+1 + EndIf + ;Now check for a 'type modifier' which is signified by the presence of a 'AS ' etc. + vt = *varArg\vt + If parseIndex < parse(subObjectIndex)\numberOfTokens-2 And LCase(parse(subObjectIndex)\tokens$[parseIndex+1]) = "as" + t1$ = LCase(parse(subObjectIndex)\tokens$[parseIndex+2]) + parseIndex + 2 + Select t1$ + Case "boolean" : vt = #VT_BOOL + Case "string", "bstr" : vt = #VT_BSTR + Case "byte" : vt = #VT_I1 + Case "ubyte" : vt = #VT_UI1 + Case "word" : vt = #VT_I2 + Case "uword" : vt = #VT_UI2 + Case "long", "dword" : vt = #VT_I4 + Case "ulong", "udword" : vt = #VT_UI4 + Case "quad", "qword" : vt = #VT_I8 + Case "uquad", "uqword" : vt = #VT_UI8 + Case "integer", "int" : vt = #VT_INT + Case "uinteger", "uint" : vt = #VT_UINT + Case "date" : vt = #VT_DATE + Case "object", "idispatch", "comateobject" : vt = #VT_DISPATCH + Case "iunknown" : vt = #VT_UNKNOWN + Case "float", "single" : vt = #VT_R4 + Case "double" : vt = #VT_R8 + Case "variant" : vt = #VT_VARIANT + Default + result = #E_INVALIDARG + Break + EndSelect + EndIf + If parseIndex < parse(subObjectIndex)\numberOfTokens-1 And LCase(parse(subObjectIndex)\tokens$[parseIndex+1]) = "byref" + blnByRef = #True + parseIndex+1 + EndIf + ;Now modify the underlying parameter depending on it's type and whether it is being passed by reference etc. + ;Note that objects being passed by reference will NOT have their reference counts increased. + If blnByRef + Select *varArg\vt + Case #VT_I1, #VT_I2, #VT_I4, #VT_I8 ;Only these types (which have already been processed) can hold an address. + *varArg\vt = vt | #VT_BYREF + Default + result = #E_INVALIDARG + Break + EndSelect + ;BYVAL. + ElseIf vt = #VT_DISPATCH + Select *varArg\vt + Case #VT_I1, #VT_I2, #VT_I4, #VT_I8 ;Only these types (which have already been processed) can hold an address. + ;Call the AddRef method manually. A corresponding Release() will ensue when we use VariantClear_() when the underlying statement is freed. + If t1$ = "comateobject" + *cObject = *varArg\pdispVal + *varArg\pdispVal = *cObject\iDisp + *cObject\iDisp\AddRef() + Else + iDispatch = *varArg\pdispVal + iDispatch\AddRef() + EndIf + *varArg\vt = #VT_DISPATCH + Default + result = #E_INVALIDARG + Break + EndSelect + ElseIf vt = #VT_UNKNOWN + Select *varArg\vt + Case #VT_I1, #VT_I2, #VT_I4, #VT_I8 ;Only these types (which have already been processed) can hold an address. + ;Call the AddRef method manually. A corresponding Release() will ensue when we use VariantClear_() when the underlying statement is freed. + iDispatch = *varArg\punkVal + iDispatch\AddRef() + *varArg\vt = #VT_UNKNOWN + Default + result = #E_INVALIDARG + Break + EndSelect + ElseIf vt = #VT_VARIANT ;We physically copy the variant into the VarArray(). + Select *varArg\vt + Case #VT_I1, #VT_I2, #VT_I4, #VT_I8 ;Only these types (which have already been processed) can hold an address. + If *varArg\llVal + result = VariantCopy_(*varArg, *varArg\llVal) + If FAILED(result) + Break + EndIf + EndIf + Default + result = #E_INVALIDARG + Break + EndSelect + ElseIf *varArg\vt <> vt + result = VariantChangeType_(*varArg, *varArg, 16, vt) + If FAILED(result) + Break + EndIf + EndIf + *hStatement\numArgs[subObjectIndex] + 1 + *varArg - SizeOf(VARIANT) + Else + result = #E_INVALIDARG + Break + EndIf + EndSelect + parseIndex+1 + Wend + Else + result = #E_OUTOFMEMORY + EndIf + ProcedureReturn result +EndProcedure +;/////////////////////////////////////////////////////////////////////////////////////////// + + +;-======================= +;-COMateEnum OBJECT CODE. +;-======================= + +;-COMateEnum CLASS METHODS. +;---------------------------------------------- + +;================================================================================= +;Returns the next object in the underlying enumeration in the form of a COMate object (zero if an error). +;The object should be released as soon as it is no longer required. +;Any HRESULT return value is accessible through the GetLastErrorCode() method of the parent COMate object. +Procedure.i COMateEnumClass_GetNextObject(*this._membersCOMateEnumClass) + Protected result.i = #S_OK, retVar.VARIANT, *newObject._membersCOMateClass + result = *this\iEV\Next(1, retVar, 0) + If result = #S_OK ;Alternative is #S_FALSE. + If retVar\vt <> #VT_DISPATCH + result = VariantChangeType_(retVar, retVar, 0, #VT_DISPATCH) + EndIf + If SUCCEEDED(result) + ;We create a new COMate object to house the new object. + *newObject = AllocateMemory(SizeOf(_membersCOMateClass)) + If *newObject + *newObject\vTable = ?VTable_COMateClass + *newObject\iDisp = retVar\pdispVal + COMate_gNumObjects+1 + Else + VariantClear_(retVar) + result = #E_OUTOFMEMORY + EndIf + Else + VariantClear_(retVar) + EndIf + EndIf + ;Set any error code. iDispatch errors will alreay have been set. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this\parent, result) + CompilerEndIf + ProcedureReturn *newObject +EndProcedure +;================================================================================= + + +;================================================================================= +;Returns a pointer to a new variant which represents the next variant in the underlying enumeration (zero if an error). +;The variant should be 'freed' by the user with VariantClear_() etc. +;Any HRESULT return value is accessible through the GetLastErrorCode() method of the parent COMate object. +Procedure.i COMateEnumClass_GetNextVariant(*this._membersCOMateEnumClass) + Protected result.i = #S_OK, *retVar.VARIANT + ;Allocate memory for a new variant. + *retVar = AllocateMemory(SizeOf(VARIANT)) + If *retVar + result = *this\iEV\Next(1, *retVar, 0) + If result <> #S_OK ;Alternative is #S_FALSE. + FreeMemory(*retVar) + *retVar = 0 + EndIf + Else + result = #E_OUTOFMEMORY + EndIf + ;Set any error code. iDispatch errors will alreay have been set. + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this\parent, result) + CompilerEndIf + ProcedureReturn *retVar +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method Resets the enumeration back to the beginning. +;Returns a HRESULT value. #S_OK for no errors. +Procedure.i COMateEnumClass_Reset(*this._membersCOMateEnumClass) + Protected result.i + If *this\iEV ;Just in case. + ;Reset underlying IEnumVARIANT object. + result = *this\iEV\Reset() + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(*this\parent, result) + CompilerEndIf + ProcedureReturn result +EndProcedure +;================================================================================= + + +;================================================================================= +;The following method releases a com object created by any of the functions which return object pointers. +Procedure COMateEnumClass_Release(*this._membersCOMateEnumClass) + If *this\iEV ;Just in case. + ;Release underlying IEnumVARIANT object. + *this\iEV\Release() + EndIf + ;Free object. + FreeMemory(*this) +EndProcedure +;================================================================================= + + +;-======================= +;-COM (ActiveX) REGISTRATION FUNCTIONS. +;-======================= + +;================================================================================= +;The following function allows the user to register a COM server for the duration of an application's run etc. +;Returns a HRESULT value. #S_OK for no errors. +Procedure.i COMate_RegisterCOMServer(dllName$, blnInitCOM = #True) + Protected result.i = #S_OK, lib.i, fn.i + If blnInitCOM + CoInitialize_(0) + EndIf + If FileSize(dllName$) > 0 + lib = OpenLibrary(#PB_Any, dllName$) + If lib + fn = GetFunction(lib, "DllRegisterServer") + If fn + result = CallFunctionFast(fn) + Else + result = #E_FAIL + EndIf + CloseLibrary(lib) + Else + result = #E_FAIL + EndIf + Else + result = #E_INVALIDARG + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(0, result) + CompilerEndIf + ProcedureReturn result +EndProcedure +;================================================================================= + + +;================================================================================= +;The following function allows the user to unregister a COM server after registering it with COMate_RegisterActiveXServer(). +;Returns a HRESULT value. #S_OK for no errors. +Procedure.i COMate_UnRegisterCOMServer(dllName$, blnInitCOM = #True) + Protected result.i = #S_OK, lib.i, fn.i + If blnInitCOM + CoInitialize_(0) + EndIf + If FileSize(dllName$) > 0 + lib = OpenLibrary(#PB_Any, dllName$) + If lib + fn = GetFunction(lib, "DllUnregisterServer") + If fn + result = CallFunctionFast(fn) + Else + result = #E_FAIL + EndIf + CloseLibrary(lib) + Else + result = #E_FAIL + EndIf + Else + result = #E_INVALIDARG + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(0, result) + CompilerEndIf + ProcedureReturn result +EndProcedure +;================================================================================= + + +;-======================= +;-MISCELLANEOUS FUNCTIONS. +;-======================= + +;================================================================================= +;The following function searches the registry for the given textual representation of an interface IID and, if successful, copies the +;actual IID to the specified buffer. +;Returns a HRESULT. +Procedure.i COMate_GetIIDFromName(name$, *iid.IID) + Protected result = #E_FAIL, error, hKey1, hKey2, enumIndex, subKey, lpcbName = 256, cbData = 256, buffer + Protected bstr + If name$ And *iid + subKey = AllocateMemory(lpcbName) + If subKey + buffer = AllocateMemory(cbData) + If buffer + If RegOpenKeyEx_(#HKEY_CLASSES_ROOT, "Interface", 0, #KEY_READ, @hKey1) = #ERROR_SUCCESS And hKey1 + enumIndex = 0 + error = RegEnumKeyEx_(hKey1, enumIndex, subKey, @lpcbName, 0, 0, 0, 0) + While error = #ERROR_SUCCESS + If RegOpenKeyEx_(hKey1, subKey, 0, #KEY_READ, @hKey2) = #ERROR_SUCCESS And hKey2 + cbData = 256 + If RegQueryValueEx_(hKey2, "", 0, 0, buffer, @cbData) = #ERROR_SUCCESS + If PeekS(buffer) = name$ ;We have the correct entry. + ;Attempt to create an IID from the string representation of the IID. + bstr = COMate_MakeBSTR(PeekS(subKey)) + If bstr + result = CLSIDFromString_(bstr, *iid) + SysFreeString_(bstr) + Else + result = #E_OUTOFMEMORY + EndIf + Break + EndIf + EndIf + RegCloseKey_(hKey2) + EndIf + lpcbName = 256 + enumIndex + 1 + error = RegEnumKeyEx_(hKey1, enumIndex, subKey, @lpcbName, 0, 0, 0, 0) + Wend + RegCloseKey_(hKey1) + EndIf + FreeMemory(buffer) + EndIf + FreeMemory(subKey) + EndIf + Else + result = #E_INVALIDARG + EndIf + CompilerIf Defined(COMATE_NOERRORREPORTING, #PB_Constant)=0 + COMateClass_INTERNAL_SetError(0, result) + CompilerEndIf + ProcedureReturn result +EndProcedure +;================================================================================= + + +;-======================= +;-ERROR RETRIEVAL FUNCTIONS. +;-======================= + +;================================================================================= +;The following function returns the last error HRESULT code recorded by COMate against the underlying thread. +;This is completely threadsafe in that 2 threads using the same COMate object will not overwrite each other's errors. +Procedure.i COMate_GetLastErrorCode() + Protected *error._COMateThreadErrors + If COMate_gErrorTLS And COMate_gErrorTLS <> -1 + *error = TlsGetValue_(COMate_gErrorTLS) + If *error + ProcedureReturn *error\lastErrorCode + EndIf + EndIf +EndProcedure +;================================================================================= + + +;================================================================================= +;The following function returns a description of the last error recorded by COMate against the underlying thread. +;This is completely threadsafe in that 2 threads using the same COMate object will not overwrite each other's errors. +Procedure.s COMate_GetLastErrorDescription() + Protected *error._COMateThreadErrors + If COMate_gErrorTLS And COMate_gErrorTLS <> -1 + *error = TlsGetValue_(COMate_gErrorTLS) + If *error + ProcedureReturn *error\lastError$ + EndIf + EndIf +EndProcedure +;================================================================================= + + + +;-======================= +;-UTILITY FUNCTIONS. +;-======================= + +;///////////////////////////////////////////////////////////////////////////////// +;The following function converts a string (Ascii or Unicode) to an OLE string. +;We access this through a prototype. +Procedure.i COMateClass_UTILITY_MakeBSTR(value) + Protected result.i + result = SysAllocString_(value) + ProcedureReturn result +EndProcedure +;///////////////////////////////////////////////////////////////////////////////// + + +DataSection + + VTable_COMateClass: + Data.i @COMateClass_Invoke() + Data.i @COMateClass_Release() + Data.i @COMateClass_CreateEnumeration() + Data.i @COMateClass_GetCOMObject() + Data.i @COMateClass_GetContainerhWnd() + Data.i @COMateClass_SetDesignTimeMode() + Data.i @COMateClass_GetDateProperty() + Data.i @COMateClass_GetIntegerProperty() + Data.i @COMateClass_GetObjectProperty() + Data.i @COMateClass_GetRealProperty() + Data.i @COMateClass_GetStringProperty() + Data.i @COMateClass_GetVariantProperty() + Data.i @COMateClass_SetProperty() + Data.i @COMateClass_SetPropertyRef() +CompilerIf Defined(COMATE_NOINCLUDEATL, #PB_Constant)=0 + Data.i @COMateClass_SetEventHandler() + Data.i @COMateClass_GetIntegerEventParam() + Data.i @COMateClass_GetObjectEventParam() + Data.i @COMateClass_GetRealEventParam() + Data.i @COMateClass_GetStringEventParam() + Data.i @COMateClass_IsEventParamPassedByRef() +CompilerEndIf + VTable_COMateEnumClass: + Data.i @COMateEnumClass_GetNextObject() + Data.i @COMateEnumClass_GetNextVariant() + Data.i @COMateEnumClass_Reset() + Data.i @COMateEnumClass_Release() + +CompilerIf Defined(COMATE_NOINCLUDEATL, #PB_Constant)=0 + VTable_COMateEventSink: + Data.i @COMateSinkClass_QueryInterface() + Data.i @COMateSinkClass_AddRef() + Data.i @COMateSinkClass_Release() + Data.i @COMateSinkClass_GetTypeInfoCount() + Data.i @COMateSinkClass_GetTypeInfo() + Data.i @COMateSinkClass_GetIDsOfNames() + Data.i @COMateSinkClass_Invoke() +CompilerEndIf + + IID_NULL: ; {00000000-0000-0000-0000-000000000000} + Data.l $00000000 + Data.w $0000, $0000 + Data.b $00, $00, $00, $00, $00, $00, $00, $00 + + 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_IClassFactory: ; {00000001-0000-0000-C000-000000000046} + Data.l $00000001 + Data.w $0000, $0000 + Data.b $C0, $00, $00, $00, $00, $00, $00, $46 + + IID_IPersistFile: ; {0000010B-0000-0000-C000-000000000046} + Data.l $0000010B + Data.w $0000, $0000 + Data.b $C0, $00, $00, $00, $00, $00, $00, $46 + + IID_IEnumVARIANT: ; {00020404-0000-0000-C000-000000000046} + Data.l $00020404 + Data.w $0000, $0000 + Data.b $C0, $00, $00, $00, $00, $00, $00, $46 + + IID_IConnectionPointContainer: ; {B196B284-BAB4-101A-B69C-00AA00341D07} + Data.l $B196B284 + Data.w $BAB4, $101A + Data.b $B6, $9C, $00, $AA, $00, $34, $1D, $07 + + IID_IAxWinAmbientDispatch: ; {B6EA2051-048A-11D1-82B9-00C04FB9942E} + Data.l $B6EA2051 + Data.w $048A, $11D1 + Data.b $82, $B9, $00, $C0, $4F, $B9, $94, $2E + +EndDataSection + +CompilerEndIf + +; IDE Options = PureBasic 5.70 LTS (Windows - x86) +; ExecutableFormat = Shared dll +; CursorPosition = 70 +; FirstLine = 25 +; Folding = --------------------- +; EnableThread +; Executable = nxReportU.dll +; CompileSourceDirectory +; EnableCompileCount = 0 +; EnableBuildCount = 0 +; EnableExeConstant +; EnableUnicode \ No newline at end of file diff --git a/COMatePLUS/COMatePLUS_Residents.pbi b/COMatePLUS/COMatePLUS_Residents.pbi new file mode 100644 index 0000000..2a8ddba --- /dev/null +++ b/COMatePLUS/COMatePLUS_Residents.pbi @@ -0,0 +1,143 @@ +;///////////////////////////////////////////////////////////////////////////////// +;***COMatePLUS*** COM OLE automation through iDispatch. +;*=========== +;* +;*©nxSoftWare (www.nxSoftware.com) 2009. +;*====================================== +;* +;*Header file. +;///////////////////////////////////////////////////////////////////////////////// + + #COMate_UnknownObjectType = 1 ;Use this with the GetObjectProperty() method when the object type does not inherit from iDispatch. + ;In such cases, the method will return the interface pointer directly (as opposed to a COMate object!) + + ;The following constant is used with the SetEventHandler() method of the COMateObject class in order to set an optional + ;'global' handler for all events (useful for examining which events are being sent etc.) + ;This is in addition to any individual handlers which are called after this global one. + #COMate_CatchAllEvents = "" + ;The following enumeration is used with the SetEventHandler() method of the COMateObject class to specify the return type + ;(if any) of an individual event. + Enumeration + #COMate_NoReturn + #COMate_IntegerReturn + #COMate_RealReturn + #COMate_StringReturn + #COMate_OtherReturn ;This is a special case; please see the COMate manual for details (SetEventHandler()). + #COMate_VariantReturn = #COMate_OtherReturn ;Alias! + #COMate_UnknownReturn = #COMate_OtherReturn ;Alias! + EndEnumeration + + +;///////////////////////////////////////////////////////////////////////////////// +;-Declaration of 'Public' functions. + Declare.i COMate_CreateObject(progID$, hWnd = 0, blnInitCOM = #True) + Declare.i COMate_GetObject(file$, progID$="", blnInitCOM = #True) + Declare.i COMate_WrapCOMObject(object.iUnknown) + ;Statement functions. + Declare.i COMate_PrepareStatement(command$) ;Returns a statement handle or zero if an error. + Declare.i COMate_GetStatementParameter(hStatement, index) ;Returns, if successful, a direct pointer to the appropriate variant structure. + ;Index is 1-based. + Declare COMate_FreeStatementHandle(hStatement) + ;The two error retrieval functions are completely threadsafe in that, for example, 2 threads could be working with the same COMate object + ;and any resuting errors will be stored separately so that one thread's errors will not conflict with another's etc. + Declare.i COMate_GetLastErrorCode() + Declare.s COMate_GetLastErrorDescription() + ;OCX (ActiveX) functions. + Declare.i COMate_RegisterCOMServer(dllName$, blnInitCOM = #True) + Declare.i COMate_UnRegisterCOMServer(dllName$, blnInitCOM = #True) + Declare.i COMate_CreateActiveXControl(x, y, width, height, progID$, blnInitCOM = #True) + ;Miscellaneous. + Declare.i COMate_GetIIDFromName(name$, *iid.IID) +;///////////////////////////////////////////////////////////////////////////////// + + +;///////////////////////////////////////////////////////////////////////////////// +;-Class interfaces. + + ;The following interface details the class methods for COMateObject type objects; the main object type for COMate. + Interface COMateObject + ;General methods. + ;================================= + Invoke.i(command$, *hStatement=0) + ;Returns a HRESULT value. #S_OK for no errors. + Release() ;DO NOT use this until all enumeration objects attached to this object have been freed. + CreateEnumeration.i(command$, *hStatement=0) + ;Returns an object of type COMateEnumObject (see below) or zero if an error. + GetCOMObject.i() ;Returns the COMate object's underlying iDispatch object pointer. AddRef() is called on this object + ;so the developer must call Release() at some point. + GetContainerhWnd.i(returnCtrlID=0) + ;In the case of an ActiveX control, this methods returns either the handle of the container used + ;to house the control or the Purebasic gadget#. Returning the gadget# is only viable if using COMate + ;as a source code include (or a Tailbitten library!) + SetDesignTimeMode.i(state=#True);In the case of an ActiveX control, this methods attempts to set a design time mode. + ;Returns a HRESULT value. #S_OK for no errors. + ;Get property methods. + ;================================= + GetDateProperty.i(command$, *hStatement=0) + ;Returns a PB date value. Of course you can always retrieve a data in string form using GetStringProperty() etc. + GetIntegerProperty.q(command$, *hStatement=0) + ;Returns a signed quad which can of course be placed into any integer variable; byte, word etc. + GetObjectProperty.i(command$, *hStatement=0, objectType = #VT_DISPATCH) + ;Returns a COMate object or an iUnknown interface pointer depending on the value of the 'objectType' parameter. + ;For 'regular' objects based upon iDispatch, leave the optional parameter 'objectType' as it is. + ;Otherwise, for unknown object types set objectType to equal #COMate_UnknownObjectType. In these cases, + ;this method will return the interface pointer directly (as opposed to a COMate object). + ;In either case the object should be released as soon as it is no longer required. + GetRealProperty.d(command$, *hStatement=0) + ;Returns a double value which can of course be placed into any floating point variable; float or double. + GetStringProperty.s(command$, *hStatement=0) + GetVariantProperty.i(command$, *hStatement=0) + ;For those returns which are not directly supported by the COMate functions. + ;The user must use VariantClear_() and FreeMemory() when finished with the variant returned by this method. + ;Set property methods. + ;================================= + SetProperty.i(command$, *hStatement=0) + ;Returns a HRESULT value. #S_OK for no errors. + SetPropertyRef.i(command$, *hStatement=0) + ;Returns a HRESULT value. #S_OK for no errors. +CompilerIf Defined(COMATE_NOINCLUDEATL, #PB_Constant)=0 + ;Event handler methods. + ;================================= + SetEventHandler.i(eventName$, callback, returnType = #COMate_NORETURN, *riid.IID=0) + ;eventName$ = "" to set an optional handler which will receive all events (useful for examining which events are sent). + ;This is in addition to any individual handlers which are called after this 'global' one. + ;Returns a HRESULT value. #S_OK for no errors. Set callback = 0 to remove an existing event handler. + GetIntegerEventParam.q(index) ;Only valid to call this during an event handler. Index is a 1-based index. + GetObjectEventParam.i(index, objectType = #VT_DISPATCH) + ;Only valid to call this during an event handler. Index is a 1-based index. + ;The object returned is NOT in the form of a COMate object. Use COMate_WrapCOMObject() to convert to + ;a COMate object if required. + ;User must call Release() on this object when done. + GetRealEventParam.d(index) ;Only valid to call this during an event handler. Index is a 1-based index. + GetStringEventParam.s(index) ;Only valid to call this during an event handler. Index is a 1-based index. + IsEventParamPassedByRef.i(index, *ptrParameter.INTEGER=0, *ptrVariant.INTEGER=0) + ;Returns zero or a variant #VT_... type constant (minus the #VT_BYREF modifier). + ;In the latter case, and if *ptrParameter is non-zero, then the address of the underlying parameter + ;is placed into this buffer, enabling the client application to modify the parameter etc. +CompilerEndIf + EndInterface + + + ;The following interface details the class methods for COMateEnumObject type objects. + ;Instances of these objects are used to enumerate collections of objects (or variants) exposed by a COM object. + ;These objects are created through the CreateEnumeration() method of the COMateObject class (see above). + Interface COMateEnumObject + GetNextObject.i() ;Returns a 'COMateObject' object (or zero if the enumeration is complete). + ;The user must use the Release() method on this object when it is no longer required. + GetNextVariant.i() ;Returns a pointer to a variant (or zero if there are no more). + ;The user must use VariantClear_() and FreeMemory() when finished with the variant returned by this method. + Reset.i() ;Resets the enumeration back to the beginning. NOTE that there is no guarantee that a second run + ;through the underlying collection will produce the same results. Imagine a collection of files in a + ;folder for example in which some can be deleted between enumerations etc. + ;Returns a HRESULT value. #S_OK for no errors. + Release() + EndInterface +;///////////////////////////////////////////////////////////////////////////////// + +; IDE Options = PureBasic 4.31 Beta 1 (Windows - x86) +; ExecutableFormat = Shared Dll +; CursorPosition = 75 +; FirstLine = 52 +; EnableUnicode +; EnableThread +; Executable = nxReportU.dll \ No newline at end of file diff --git a/DYMO.pbi b/DYMO.pbi new file mode 100644 index 0000000..7cd7b6c --- /dev/null +++ b/DYMO.pbi @@ -0,0 +1,732 @@ +EnableExplicit + +; DYMO Label Software (DLS) have to be installed. +; This Include is created for DLS v.8+ (year 2015+). +; Maybe it works with lower version, but this is untested. + + +; Constants +; =========================================================== + +; For Printers with more than one tray +Enumeration DYMO_Tray + #DYMO_Tray_Unknown = -1 + #DYMO_Tray_Left = 0 + #DYMO_Tray_Right = 1 + #DYMO_Tray_Auto = 2 +EndEnumeration + +; for DYMO_SetAddressPOSTNET(POSTNET_Pos) +#DYMO_POSTNET_Pos_None = "NONE" +#DYMO_POSTNET_Pos_Top = "TOP" +#DYMO_POSTNET_Pos_Buttom = "BUTTOM" + +; not really needed, but nice to know +#DYMO_False = #False ; 0 +#DYMO_True = ~#DYMO_False ; -1 + + +; Initialize all needed components or release them +; =========================================================== + +DeclareDLL DYMO_Init() +; Use this BEFORE any use of DYMO_*() commands. +; Prevent any use of DYMO_*() procedures if return value is not #True. +; Return: #True or #False + +DeclareDLL DYMO_Release() +; Release all objects created with DYMO_Init() +; After using DYMO_Release() stop using any DYMO_*() command. +; If you want to reuse DYMO_* commands, you can call DYMO_Init() again. +; Return: void + + +; Manage Printer(s) and printing +; =========================================================== + +DeclareDLL DYMO_ExaminePrinters() +; Examine available DYMO printers +; Return: Number of available printers + +DeclareDLL.s DYMO_NextPrinter() +; Cycle through the List of DYMO-Printer examined with DYMO_ExaminePrinters() +; Return: Printer name or #Null$ if no more printers available + +DeclareDLL.s DYMO_GetCurrentPrinterName() +; Get the name of the currently selected printer +; Return: selected printer name + +DeclareDLL DYMO_SelectPrinter(PrinterName.s) +; Redirects output to the selected printer. PrinterName is of the +; form "Printer name on Port". Returns TRUE on success, FALSE +; on error. Example: +; To Select the , you would use the +; command: DYMO_SelectPrinter("DYMO LabelWriter EL60 on COM3:") +; Return: #DYMO_True or #DYMO_False + +DeclareDLL DYMO_IsTwinTurboPrinter(PrinterName.s) +; Returns TRUE if the specified printer (PrinterName) is a +; LabelWriter Twin Turbo, FALSE otherwise. +; Return: #DYMO_True or #DYMO_False + +DeclareDLL DYMO_SetPrintMode(HighQuality = #True) +; When "HighQuality" is set to TRUE (Default value), labels containing barcode(s) +; will print at high quality mode but the print speed is reduced. +; Unsetting this mode will cause all labels to print at the fasted print +; speed. + +DeclareDLL DYMO_GetCurrentPaperTray() +; Further Information: When the currently selected printer is a +; LabelWriter Twin Turbo, DYMO Label software attempts To +; associate a paper tray With the currently opened label file. As an +; example, If the last label printed on the left tray was "Address +; 30252" And the last label printed on the right tray was "Shipping +; 30323", then when the user opens a label file that uses the +; "Address 30252" paper size, DYMO Label software automatically +; sets the tray selection To left tray. +; Return: the current active paper tray +; Possible Return values include: +; #DYMO_Tray_Unknown = Unknown Tray (program user must specify) +; #DYMO_Tray_Left = Left Tray (Roll) +; #DYMO_Tray_Right = Right Tray (Roll) +; #DYMO_Tray_Auto = Auto Switch + +DeclareDLL DYMO_IsPrinterOnline(PrinterName.s) +; This applies to locally connected printers only. Shared printers +; always return true. Returns true if the specified printer is online, +; false if the printer is offline. +; Return: #DYMO_True or #DYMO_False + +DeclareDLL DYMO_StartPrintJob() +DeclareDLL DYMO_StopPrintJob() +; Wrapping DYMO_PrintLabel() calls within the DYMO_StartPrintJob() and +; DYMO_EndPrintJob() calls will cause labels to be printed as pages of the +; same print job. +; The benefit is seen with reduced the print job. +; +; Example: +; ; this printing loop creates a 10 page print job +; DYMO_StartPrintJob() +; For i = 1 to 10 +; ; update some fields on the label +; DYMO_PrintLabel() ; print one label +; Next +; DYMO_StopPrintJob(); +; +; this code above will print labels much faster than the code below:  +; +; ; this printing loop creates 10 different one page print jobs +; For i = 1 to 10 +; ; update some fields on the label +; DYMO_PrintLabel() ; print one label +; Next +; +; Return: void + +DeclareDLL DYMO_PrintLabel(Copies = 1, Tray = #DYMO_Tray_Unknown, ShowDialog = #False) +; Prints the current label. "Copies" is the number of copies to print. +; "ShowDialog" controls the display of the print-progress dialog. If +; TRUE, then the dialog is displayed. Returns TRUE on success, +; FALSE on error. +; Note: When the currently selected printer is a LabelWriter Twin Turbo, this command defaults to +; use the left roll. +; Possible values For the "Tray" parameter include: +; #DYMO_Tray_Left = Left Roll +; #DYMO_Tray_Right = Right Roll +; #DYMO_Tray_Auto = Auto Switch - This puts the printer in a mode where it starts to +; print from the last printed roll and automatically switch over to the +; other roll when the starting roll runs out of paper. It continues to +; toggle back and forth between rolls as long as the user refills rolls +; once they become empty. This mode of printing is useful when the +; user is printing a large number of labels. +; Return: #DYMO_True or #DYMO_False + + +; Automatic creation of print-jobs +; =========================================================== + +DeclareDLL DYMO_SmartPasteFromClipboard() +; Parses text data in the Clipboard into records and prints a label for +; each record. +; Return: #DYMO_True if the operation was successful, +; #DYMO_False if the operation failed. + +DeclareDLL DYMO_SmartPasteFromFile(File.s) +; Parses comma or tab delimited data in a file into records and prints +; a label For each record. +; Return: #DYMO_True if the operation was successful, +; #DYMO_False if the operation failed. + +DeclareDLL DYMO_SmartPasteFromString(Text.s) +; Parses text data in "Text" into records and prints a label for each +; record. +; Return: #DYMO_True if the operation was successful, +; #DYMO_False if the operation failed. + + +; Manage .label files +; =========================================================== + +DeclareDLL DYMO_OpenMemory(*Buffer, BufferSize) +; Reads a label file from a buffer (vs. from a file or URL). This is +; useful If you intend to manage the binary data yourself. The +; buffer must be filled with the binary Data of the label file. +; Return: #DYMO_True if the label file was Read from the buffer correctly. +; #DYMO_False if the buffer is invalid. + +DeclareDLL DYMO_SaveMemory() +; Returns a pointer, which is actually containing +; the binary data of the label file currently open in DYMO Label +; software. +; You can use MemorySize() tu get the size of the buffer. +; If you not longer need the data use FreeMemory() +; Return: *Buffer + +DeclareDLL DYMO_OpenURL(URL.s) +; Opens a label file using an URL. The URL can start with http, https, +; ftp, or file, etc. +; Return: #DYMO_True if the file was opened successfully, +; #DYMO_False if the file does not exist. + +DeclareDLL DYMO_OpenLabel(File.s, ShowDialogBoxIfFail = #False) +; Opens a label file. Returns TRUE on success, FALSE on error. +; *Functional Difference Alert: +; The function will try to open the specified label file name With the .label extension first, even If +; the parameter specifies a different file extension. +; For example, If your application calls: +; DYMO_OpenLabel("mylabel.lwl") +; The function will try to look for the file in the following order: +; mylabel.label +; mylabel.lwl +; mylabel.lwt +; * The reason for this behavior has to do with how the implementation handles both ".lwl" and +; ".label" file formats. The implementation converts ".lwl" format into ".label" format internally +; before performing any actions on a label file. What this means is that when a label that was +; opened as ".lwl" will be saved as a ".label" file if the DYMO_SaveLabel() method is called. +; So if an SDK application opens a ".lwl" label file, modifies it, then saves the file. The file would +; be saved as a ".label" file. When the application returns to open the same ".lwl" file expecting to +; see the modifications, the DYMO_OpenLabel() procedure would need to open the ".label" file for the +; modification to be seen. +; If "ShowDIalogBoxIfFail" is set to TRUE and the specified file name is not found, opens the +; Label File Open dialog box. +; Return: #DYMO_True if the file was opened successfully, +; #DYMO_False if the file does not exist. + +DeclareDLL DYMO_SaveLabel(File.s = #Null$) +; Saves the current label. Returns TRUE on success, FALSE on +; error. If a "File" is given, saves the current label under a new name. +; *Functional Difference Alert: +; The function will save the specified label file name in the .label file extension, even if the +; parameter specifies a different file extension. +; For example, If your application calls: +; DYMO_SaveLabel("SomeFile.lwl") +; the function will save the file As "SomeFile.label". The label file is in the new DYMO Label v.8 +; .label file format. + +; Manage Most Recently Used (MRU) .label files +; =========================================================== + +DeclareDLL DYMO_MRU_GetFileCount() +; Return: the number of files in the MRU label file list. + +DeclareDLL DYMO_MRU_OpenFile(Index) +; Returns a label file name from the MRU label files List. The "Index" +; parameter identifies which file name in the MRU to return. The +; index is zero-based and the file name DOES NOT include the file +; path or extension. Example: "SomeFile" + +DeclareDLL.s DYMO_MRU_GetFileName(Index) + +DeclareDLL DYMO_MRU_ExamineFiles() +; Examine available MRU files +; Return: Number of available Files + + +DeclareDLL.s DYMO_MRU_NextFile() +; Cycle through the MRU-List examined with DYMO_MRU_ExamineFiles() +; Return: Filename or #Null$ if no more available + + +; Proxy-settings (for commands with URL) +; =========================================================== + +DeclareDLL DYMO_ProxySetup(Protocol.s, ServerName.s, Port.l, ProxyBypass.s, UserName.s, Password.s) +; Allows customized proxy settings (different from IE’s Default +; proxy settings). All URL related function calls in the SDK will +; adhere to these proxy settings. + +DeclareDLL DYMO_ProxyClearSettings() +; Clears all proxy settings and revert back to using IE’s default +; proxy settings. + +DeclareDLL DYMO_ProxyBypass(Set = #True) ; #False = default +; Setting the property to TRUE will cause all URL related SDK +; functions To bypass any proxy settings, including IE’s Default +; proxy settings. +; Setting the property to FALSE (the Default value) means all URL +; related SDK functions will use either IE’s Default proxy setting or +; the user specified proxy settings + + +; Manage currently loaded .label and modify objects +; =========================================================== + +DeclareDLL DYMO_ExamineObjects(VariableOnly = #True) +; Examine available objects in the current loaded label. If "VariableOnly" is set to +; TRUE then only variable Objects are examined. +; Return: Number of Objects + +DeclareDLL.s DYMO_NextObject() +; Cycle through the objects examined with DYMO_ExamineObjectes() +; Return: ObjectName or #Null$ if no more available + +DeclareDLL DYMO_GetAddressFieldCount() +; This procedure returns the number of address objects on the current +; label. Used to determine possible values for the index parameter of +; the DYMO_SetAddressPOSTNET() and DYMO_SetAddress functions. + +DeclareDLL.s DYMO_GetText(Object.s) +; Given an "Object" name returns the contents of the object. +; This operation only applies to address, barcode and text objects. + +DeclareDLL DYMO_SetAddress(Address.s, Index = 1) +; Given an "Index" of an address object, places the text in the object. +; The index is normally 1, but for designs with more than one +; address object, the index can be greater than one to select other +; address objects. +; Return: #DYMO_True on success or #DYMO_False on error + +DeclareDLL DYMO_SetField(Object.s, Text.s) +; Given an object name, and some text, changes the text of the object +; to have the new text. This operation only applies to address, +; barcode, and text objects. +; Return: #DYMO_True on success or #DYMO_False on error + +DeclareDLL DYMO_SetAddressPOSTNET(POSTNET_Pos.s, Index = 1) +; Given an index of an address object, changes the POSTNET +; barcode setting for the object. The index is normally 1, but for +; designs with more than one address object, the index can be greater +; than one to select other address objects. +; Position can be #DYMO_POSTNET_Pos_None, +; #DYMO_POSTNET_Pos_Top or #DYMO_POSTNET_Pos_Buttom +; Return: void + +DeclareDLL DYMO_PasteFromClipboard(Object.s) +; Paste text from the clipboard to an object by the given +; "Object" name. +; Return: #DYMO_True on success or #DYMO_False on error + +DeclareDLL DYMO_SetImageFile(Object.s, File.s) +; Load an image file to a graphic object by the given "Object" name. +; Return: #DYMO_True on success or #DYMO_False on error + +DeclareDLL DYMO_SetImageURL(Object.s, URL.s) +; Allows specifying URL as the image source for an image object on +; the label. +; Return: #DYMO_True on success or #DYMO_False on error + +DeclareDLL DYMO_PasteImageFromClipboard(Object.s) +; Paste image from the clipboard to an object by the given +; "Object" name. +; Return: #DYMO_True on success or #DYMO_False on error + + +; Internally used Procedures +; =========================================================== + +Declare INTERNAL_DYMO_Variant2Buffer(*Var.VARIANT);Return: *Mem Pointer (use FreeMemory() / MemorySize()) +Declare INTERNAL_DYMO_Buffer2Variant(*Buffer, BufferSize);Return: *Variant, use VariantClear_() AND ClearStructure() !! + + +; some tests for the include +; =========================================================== +CompilerIf Defined(INCLUDE_DYMO, #PB_Constant) ; if DYMO / DYMO_DLL is already included + CompilerError "<" + #PB_Compiler_Filename + "> DYMO already included !!" +CompilerElse + #INCLUDE_DYMO = #True +CompilerEndIf +CompilerIf Defined(INCLUDE_COMATE, #PB_Constant) = #False ; if COMatePLUS is not included + XIncludeFile "COMatePLUS/COMatePLUS_Residents.pbi" + XIncludeFile "COMatePLUS/COMatePLUS.pbi" + ;CompilerWarning "<" + #PB_Compiler_Filename + ~"> if you want to include other COMatePLUS Version, you have to include \"COMatePLUS.pbi\"" +CompilerEndIf +CompilerIf #PB_Compiler_Unicode = #False + CompilerError "<" + #PB_Compiler_Filename + "> Needs Unicode!!" +CompilerEndIf + + +; Structures +; =========================================================== + +Structure DYMO_Struct_COM + AddIn.COMateObject + Labels.COMateObject +EndStructure +Structure DYMO_Struct_RetVar + NextPrinter.s + GetCurrentPrinterName.s + MRU_NextFile.s + MRU_GetFileName.s + NextObject.s + GetText.s +EndStructure +Structure DYMO_Struct + COM.DYMO_Struct_COM + List Printers.s() + List MRU_Files.s() + List Objects.s() + Initialized.i + RetVar.DYMO_Struct_RetVar +EndStructure + + +; Procedures +; =========================================================== + +ProcedureDLL DYMO_Init() + Global DYMO.DYMO_Struct + + ; create needed COMate objects + If Not DYMO\Initialized + DYMO\COM\AddIn = COMate_CreateObject("Dymo.DymoAddIn") + DYMO\COM\Labels = COMate_CreateObject("Dymo.DymoLabels") + EndIf + + If DYMO\COM\AddIn And DYMO\COM\Labels + DYMO\Initialized = #True + EndIf + + ProcedureReturn DYMO\Initialized +EndProcedure +ProcedureDLL DYMO_Release() + + ; release COMate objects + If DYMO\Initialized + If DYMO\COM\AddIn + DYMO\COM\Labels\Release() + EndIf + If DYMO\COM\Labels + DYMO\COM\AddIn\Release() + EndIf + DYMO\Initialized = #False + EndIf + + ClearList(DYMO\MRU_Files()) + ClearList(DYMO\Objects()) + ClearList(DYMO\Printers()) + +EndProcedure + +ProcedureDLL DYMO_ExaminePrinters() + Protected Temp.s, i + ClearList(DYMO\Printers()) + + ; get string vom dls + Temp.s = DYMO\COM\AddIn\GetStringProperty("GetDymoPrinters()") + + ; split string and fill list + For i = 0 To CountString(Temp, "|") + AddElement(DYMO\Printers()) + DYMO\Printers() = StringField(Temp, i + 1, "|") + Next + + ResetList(DYMO\Printers()) + ProcedureReturn ListSize(DYMO\Printers()) +EndProcedure +ProcedureDLL.s DYMO_NextPrinter() + DYMO\RetVar\NextPrinter = #Null$ + + If NextElement(DYMO\Printers()) + DYMO\RetVar\NextPrinter = DYMO\Printers() + EndIf + + ProcedureReturn DYMO\RetVar\NextPrinter +EndProcedure +ProcedureDLL DYMO_SelectPrinter(PrinterName.s) + + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("SelectPrinter('" + PrinterName + "')") +EndProcedure +ProcedureDLL DYMO_IsTwinTurboPrinter(PrinterName.s) + + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("IsTwinTurboPrinter('" + PrinterName + "')") +EndProcedure +ProcedureDLL DYMO_GetCurrentPaperTray() + + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("GetCurrentPaperTray()"); +EndProcedure +ProcedureDLL.s DYMO_GetCurrentPrinterName() + DYMO\RetVar\GetCurrentPrinterName = DYMO\COM\AddIn\GetStringProperty("GetCurrentPrinterName()") + ProcedureReturn DYMO\RetVar\GetCurrentPrinterName +EndProcedure +ProcedureDLL DYMO_StartPrintJob() + + DYMO\COM\AddIn\Invoke("StartPrintJob()") +EndProcedure +ProcedureDLL DYMO_StopPrintJob() + + DYMO\COM\AddIn\Invoke("EndPrintJob()") +EndProcedure +ProcedureDLL DYMO_OpenLabel(File.s, ShowDialogBoxIfFail = #False) + + If ShowDialogBoxIfFail + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("Open2('" + File + "')") + Else + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("Open('" + File + "')") + EndIf + +EndProcedure +ProcedureDLL DYMO_SaveLabel(File.s = #Null$) + + If File = #Null$ + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("Save()") + Else + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("SaveAs('" + File + "')") + EndIf + +EndProcedure +ProcedureDLL DYMO_PrintLabel(Copies = 1, Tray = #DYMO_Tray_Unknown, ShowDialog = #False) + + Select Tray + Case #DYMO_Tray_Left, #DYMO_Tray_Right, #DYMO_Tray_Auto + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("Print2(" + Str(Copies) + "," + Str(ShowDialog) + "," + Str(Tray) + ")") + Default + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("Print(" + Str(Copies) + "," + Str(ShowDialog) + ")") + EndSelect + +EndProcedure +ProcedureDLL DYMO_IsPrinterOnline(PrinterName.s) + + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("IsPrinterOnline('" + PrinterName + "')") +EndProcedure +ProcedureDLL DYMO_OpenMemory(*Buffer, BufferSize) + Protected *Var.VARIANT + Protected Ret = #False + + ; Create Variant bufffer and copy data + *Var = INTERNAL_DYMO_Buffer2Variant(*Buffer, BufferSize) + + If *Var + Ret = DYMO\COM\AddIn\GetIntegerProperty("OpenStream(" + Str(*Var) + " AS VARIANT BYREF)") + VariantClear_(*Var) + ClearStructure(*Var, VARIANT) + EndIf + + ProcedureReturn Ret +EndProcedure +ProcedureDLL DYMO_SaveMemory() + Protected *Var.VARIANT + Protected *Ret = #Null + + ; get return *variant from property + *Var = DYMO\COM\AddIn\GetVariantProperty("SaveStream()") + If *Var + *Ret = INTERNAL_DYMO_Variant2Buffer(*Var) ; allocate some memory and copy data + VariantClear_(*Var) + EndIf + + ProcedureReturn *Ret +EndProcedure +ProcedureDLL DYMO_OpenURL(URL.s) + + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("OpenURL('" + URL + "')") +EndProcedure +ProcedureDLL DYMO_MRU_ExamineFiles() + Protected Temp.s, i + ClearList(DYMO\MRU_Files()) + + ; get string from dls + Temp.s = DYMO\COM\AddIn\GetStringProperty("GetMRULabelFiles()") + + ; split string and fill list + For i = 0 To CountString(Temp, "|") + AddElement(DYMO\MRU_Files()) + DYMO\MRU_Files() = StringField(Temp, i + 1, "|") + Next + + ResetList(DYMO\MRU_Files()) + ProcedureReturn ListSize(DYMO\MRU_Files()) +EndProcedure +ProcedureDLL.s DYMO_MRU_NextFile() + DYMO\RetVar\MRU_NextFile = #Null$ + + If NextElement(DYMO\MRU_Files()) + DYMO\RetVar\MRU_NextFile = DYMO\MRU_Files() + EndIf + + ProcedureReturn DYMO\RetVar\MRU_NextFile +EndProcedure +ProcedureDLL DYMO_MRU_GetFileCount() + + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("GetMRULabelFileCount()") +EndProcedure +ProcedureDLL.s DYMO_MRU_GetFileName(Index) + DYMO\RetVar\MRU_GetFileName = DYMO\COM\AddIn\GetStringProperty("GetMRULabelFileName(" + Str(Index) + ")") + ProcedureReturn DYMO\RetVar\MRU_GetFileName +EndProcedure +ProcedureDLL DYMO_MRU_OpenFile(Index) + + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("OpenMRULabelFile(" + Str(Index) + ")") +EndProcedure +ProcedureDLL DYMO_SetPrintMode(HighQuality = #True) + + If HighQuality + DYMO\COM\AddIn\Invoke("SetGraphicsAndBarcodePrintMode(#True)") + Else + DYMO\COM\AddIn\Invoke("SetGraphicsAndBarcodePrintMode(#False)") + EndIf + +EndProcedure +ProcedureDLL DYMO_SmartPasteFromClipboard() + + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("SmartPasteFromClipboard()") +EndProcedure +ProcedureDLL DYMO_SmartPasteFromFile(File.s) + + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("SmartPasteFromFile('" + File + "')") +EndProcedure +ProcedureDLL DYMO_SmartPasteFromString(Text.s) + + ProcedureReturn DYMO\COM\AddIn\GetIntegerProperty("SmartPasteFromString('" + Text + "')") +EndProcedure +ProcedureDLL DYMO_ProxySetup(Protocol.s, ServerName.s, Port.l, ProxyBypass.s, UserName.s, Password.s) + + DYMO\COM\AddIn\Invoke("SetupProxySettings('" + + Protocol + "','" + + ServerName + "'," + + Str(Port) + ",'" + + ProxyBypass + "','" + + UserName + "','" + + Password + "')") +EndProcedure +ProcedureDLL DYMO_ProxyClearSettings() + + DYMO\COM\AddIn\Invoke("ClearProxySettings()") +EndProcedure +ProcedureDLL DYMO_ProxyBypass(Set = #True) ; #False = default + + If Set + DYMO\COM\AddIn\SetProperty("proxyBypass = #True") + Else + DYMO\COM\AddIn\SetProperty("proxyBypass = #False") + EndIf + +EndProcedure +ProcedureDLL DYMO_ExamineObjects(VariableOnly = #True) + Protected Temp.s, i + ClearList(DYMO\Objects()) + + ; get string of objects + If VariableOnly + Temp.s = DYMO\COM\Labels\GetStringProperty("GetObjectNames(#True)") + Else + Temp.s = DYMO\COM\Labels\GetStringProperty("GetObjectNames(#False)") + EndIf + + ; split string and fill list + For i = 0 To CountString(Temp, "|") + AddElement(DYMO\Objects()) + DYMO\Objects() = StringField(Temp, i + 1, "|") + Next + + ResetList(DYMO\Objects()) + ProcedureReturn ListSize(DYMO\Objects()) +EndProcedure +ProcedureDLL.s DYMO_NextObject() + DYMO\RetVar\NextObject = #Null$ + + If NextElement(DYMO\Objects()) + DYMO\RetVar\NextObject = DYMO\Objects() + EndIf + + ProcedureReturn DYMO\RetVar\NextObject +EndProcedure +ProcedureDLL.s DYMO_GetText(Object.s) + DYMO\RetVar\GetText = DYMO\COM\Labels\GetStringProperty("GetText('" + Object + "')") + ProcedureReturn DYMO\RetVar\GetText +EndProcedure +ProcedureDLL DYMO_SetAddress(Address.s, Index = 1) + + ProcedureReturn DYMO\COM\Labels\GetIntegerProperty("SetAddress(" + Str(Index) + ",'" + Address + "')") +EndProcedure +ProcedureDLL DYMO_SetField(Object.s, Text.s) + + ProcedureReturn DYMO\COM\Labels\GetIntegerProperty("SetField('" + Object + "','" + Text + "')") +EndProcedure +ProcedureDLL DYMO_GetAddressFieldCount() + + ProcedureReturn DYMO\COM\Labels\GetIntegerProperty("AddressFieldCount()") +EndProcedure +ProcedureDLL DYMO_SetAddressPOSTNET(POSTNET_Pos.s, Index = 1) + + DYMO\COM\Labels\Invoke("POSTNET(" + Str(Index) + ",'" + POSTNET_Pos + "')") +EndProcedure +ProcedureDLL DYMO_SetImageFile(Object.s, File.s) + + ProcedureReturn DYMO\COM\Labels\GetIntegerProperty("SetImageFile('" + Object + "','" + File + "')") +EndProcedure +ProcedureDLL DYMO_SetImageURL(Object.s, URL.s) + + ProcedureReturn DYMO\COM\Labels\GetIntegerProperty("SetImageURL('" + Object + "','" + URL + "',#NUllString)") +EndProcedure +ProcedureDLL DYMO_PasteFromClipboard(Object.s) + + ProcedureReturn DYMO\COM\Labels\GetIntegerProperty("PasteFromClipboard('" + Object + "')") +EndProcedure +ProcedureDLL DYMO_PasteImageFromClipboard(Object.s) + + ProcedureReturn DYMO\COM\Labels\GetIntegerProperty("PasteImageFromClipboard('" + Object + "')") +EndProcedure + +Procedure INTERNAL_DYMO_Variant2Buffer(*Var.VARIANT) + Protected Size, *Ret = #Null, *SafeArray.SAFEARRAY + + If *Var And *Var\vt = #VT_ARRAY|#VT_UI1 And *Var\parray + *SafeArray = *Var\parray + Size = *SafeArray\rgsabound[0]\cElements - *SafeArray\rgsabound[0]\lLbound + If Size + *Ret = AllocateMemory(Size) + If *Ret + If SafeArrayLock_(*SafeArray) = #S_OK + CopyMemory(*SafeArray\pvData, *Ret, Size) + SafeArrayUnlock_(*SafeArray) + Else + FreeMemory(*Ret) + *Ret = #Null + EndIf + EndIf + EndIf + EndIf + + ProcedureReturn *Ret +EndProcedure +Procedure INTERNAL_DYMO_Buffer2Variant(*Buffer, BufferSize) + Protected *SafeArray.SAFEARRAY, SafeArrayBound.SAFEARRAYBOUND + Protected *Ret_Variant.VARIANT = AllocateStructure(VARIANT) + + If *Ret_Variant And *Buffer And BufferSize > 0 + VariantClear_(*Ret_Variant) + SafeArrayBound\lLbound = 0 + SafeArrayBound\cElements = BufferSize + *SafeArray = SafeArrayCreate_(#VT_UI1, 1, SafeArrayBound) + If *SafeArray + If SafeArrayLock_(*SafeArray) = #S_OK + CopyMemory(*Buffer, *SafeArray\pvData, BufferSize) + *Ret_Variant\vt = #VT_ARRAY|#VT_UI1 + *Ret_Variant\parray = *SafeArray + SafeArrayUnlock_(*SafeArray) + EndIf + EndIf + EndIf + + ProcedureReturn *Ret_Variant +EndProcedure + +DisableExplicit +; CursorPosition = 1 +; Folding = AAAAAAAA- +; EnableXP +; CompileSourceDirectory +; EnableCompileCount = 0 +; EnableBuildCount = 0 +; EnableExeConstant +; EnableUnicode \ No newline at end of file diff --git a/DYMO_CreateDLL.pb b/DYMO_CreateDLL.pb new file mode 100644 index 0000000..fd617b7 --- /dev/null +++ b/DYMO_CreateDLL.pb @@ -0,0 +1,13 @@ +; This is a dummy file ... for easy creation of DLL's +; see DYMO-Project ("DYMO.pbp") + +XIncludeFile "DYMO.pbi" + + +; ExecutableFormat = Shared dll +; CursorPosition = 1 +; Executable = DYMO.dll +; CompileSourceDirectory +; EnableCompileCount = 0 +; EnableBuildCount = 0 +; EnableExeConstant \ No newline at end of file diff --git a/DYMO_DLL.pbi b/DYMO_DLL.pbi new file mode 100644 index 0000000..7369490 --- /dev/null +++ b/DYMO_DLL.pbi @@ -0,0 +1,116 @@ +EnableExplicit + +; if you want to change some settings, create your own constants before include this file +CompilerIf Defined(DYMO_DLL_ImportFile_32bit, #PB_Constant) = #False + #DYMO_DLL_ImportFile_32bit = "DYMO32.lib" +CompilerEndIf +CompilerIf Defined(DYMO_DLL_ImportFile_64bit, #PB_Constant) = #False + #DYMO_DLL_ImportFile_64bit = "DYMO64.lib" +CompilerEndIf +CompilerIf Defined(INCLUDE_DYMO, #PB_Constant) ; if DYMO / DYMO_DLL is already included + CompilerError "<" + #PB_Compiler_Filename + "> DYMO already included !!" +CompilerElse + #INCLUDE_DYMO = #True +CompilerEndIf + + +CompilerSelect #PB_Compiler_Processor + CompilerCase #PB_Processor_x86 + #INTERNAL_DYMO_Import_File = #DYMO_DLL_ImportFile_32bit + Import #INTERNAL_DYMO_Import_File + INTERNAL_DYMO_GetCurrentPrinterName() As "_DYMO_GetCurrentPrinterName@0" + INTERNAL_DYMO_NextPrinter() As "_DYMO_NextPrinter@0" + INTERNAL_DYMO_MRU_NextFile() As "_DYMO_MRU_NextFile@0" + INTERNAL_DYMO_NextObject() As "_DYMO_NextObject@0" + INTERNAL_DYMO_GetText(Object.s) As "_DYMO_GetText@4" + INTERNAL_DYMO_MRU_GetFileName(Index) As "_DYMO_MRU_GetFileName@4" + EndImport + + CompilerCase #PB_Processor_x64 + #INTERNAL_DYMO_Import_File = #DYMO_DLL_ImportFile_64bit + Import #INTERNAL_DYMO_Import_File + INTERNAL_DYMO_GetCurrentPrinterName() As "DYMO_GetCurrentPrinterName" + INTERNAL_DYMO_NextPrinter() As "DYMO_NextPrinter" + INTERNAL_DYMO_MRU_NextFile() As "DYMO_MRU_NextFile" + INTERNAL_DYMO_NextObject() As "DYMO_NextObject" + INTERNAL_DYMO_GetText(Object.s) As "DYMO_GetText" + INTERNAL_DYMO_MRU_GetFileName(Index) As "DYMO_MRU_GetFileName" + EndImport +CompilerEndSelect + +Enumeration DYMO_Tray + #DYMO_Tray_Unknown = -1 + #DYMO_Tray_Left = 0 + #DYMO_Tray_Right = 1 + #DYMO_Tray_Auto = 2 +EndEnumeration + +#DYMO_POSTNET_Pos_None = "NONE" +#DYMO_POSTNET_Pos_Top = "TOP" +#DYMO_POSTNET_Pos_Buttom = "BUTTOM" + +Import #INTERNAL_DYMO_Import_File + DYMO_Init() + DYMO_Release() + + DYMO_ExaminePrinters() + DYMO_SelectPrinter(PrinterName.s) + DYMO_IsTwinTurboPrinter(PrinterName.s) + DYMO_GetCurrentPaperTray() + DYMO_StartPrintJob() + DYMO_StopPrintJob() + DYMO_OpenLabel(File.s, ShowDialogBoxIfFail = #False) + DYMO_SaveLabel(File.s = #Null$) + DYMO_PrintLabel(Copies = 1, ShowDialog = #False, Tray = #DYMO_Tray_Unknown) + DYMO_IsPrinterOnline(PrinterName.s) + DYMO_OpenMemory(*Buffer, BufferSize) + DYMO_SaveMemory() + DYMO_OpenURL(URL.s) + DYMO_MRU_ExamineFiles() + DYMO_MRU_GetFileCount() + DYMO_MRU_OpenFile(Index) + DYMO_SetPrintMode(HighQuality = #True) + DYMO_SmartPasteFromClipboard() + DYMO_SmartPasteFromFile(File.s) + DYMO_SmartPasteFromString(Text.s) + DYMO_ProxySetup(Protocol.s, ServerName.s, Port.l, ProxyBypass.s, UserName.s, Password.s) + DYMO_ProxyClearSettings() + DYMO_ProxyBypass(Set = #True) ; #False = default + DYMO_ExamineObjects(VariableOnly = #True) + DYMO_SetAddress(Address.s, Index = 1) + DYMO_SetField(Object.s, Text.s) + DYMO_GetAddressFieldCount() + DYMO_SetAddressPOSTNET(POSTNET_Pos.s, Index = 1) + DYMO_SetImageFile(Object.s, File.s) + DYMO_SetImageURL(Object.s, URL.s) + DYMO_PasteFromClipboard(Object.s) + DYMO_PasteImageFromClipboard(Object.s) +EndImport + +Macro DYMO_GetCurrentPrinterName() + PeekS(INTERNAL_DYMO_GetCurrentPrinterName()) +EndMacro +Macro DYMO_NextPrinter() + PeekS(INTERNAL_DYMO_NextPrinter()) +EndMacro +Macro DYMO_MRU_NextFile() + PeekS(INTERNAL_DYMO_MRU_NextFile()) +EndMacro +Macro DYMO_NextObject() + PeekS(INTERNAL_DYMO_NextObject()) +EndMacro +Macro DYMO_GetText(__Object_s__) + PeekS(INTERNAL_DYMO_GetText(__Object_s__)) +EndMacro +Macro DYMO_MRU_GetFileName(__Index__) + PeekS(INTERNAL_DYMO_MRU_GetFileName(__Index__) +EndMacro + +DisableExplicit +; CursorPosition = 1 +; Folding = A5 +; EnableXP +; CompileSourceDirectory +; EnableCompileCount = 0 +; EnableBuildCount = 0 +; EnableExeConstant \ No newline at end of file diff --git a/DYMO_Example.pb b/DYMO_Example.pb new file mode 100644 index 0000000..4cbf385 --- /dev/null +++ b/DYMO_Example.pb @@ -0,0 +1,188 @@ +; if you want to use your version of COMatePLUS include it before include DYMO +;#COMATE_NOINCLUDEATL = #True ; Works, if wanted +;XIncludeFile "COMatePLUS\COMatePLUS_Residents.pbi" ; Include this file too or use IncludePath +;XIncludeFile "COMatePLUS\COMatePLUS.pbi" ; Include COMatePLUS + +; include DYMO.pbi !OR! DYMO_DLL.pbi +XIncludeFile "DYMO.pbi" ; use DYMO include (with COMatePLUS) +;XIncludeFile "DYMO_DLL.pbi" ; use DYMO32.dll / DYMO64.dll + + +EnableExplicit + +OpenConsole("DYMO Example") + +; Show Objects in current loaded .label +Procedure ShowObjects(VariableOnly = #True) + Protected NrObjects, Object.s, i + NrObjects = DYMO_ExamineObjects(VariableOnly) ; #False = we want to list all object, not only those who can be changed + If NrObjects > 0 + For i = 0 To NrObjects - 1 + Object = DYMO_NextObject() + PrintN(#TAB$ + "Object: " + Object + " - Value: " + DYMO_GetText(Object)) + Next + Else + PrintN("NO Objects found") + EndIf +EndProcedure + + +Define i + +; first of all we have to initialize some things +If Not DYMO_Init() + MessageRequester("Error", "DYMO-Objects couldn't be created!") + End +EndIf + + +; search and list printer(s) +Define NrPrinters, PName.s +NrPrinters = DYMO_ExaminePrinters() +PrintN("DYMO-Printer found: " + Str(NrPrinters)) + +; list all printers +If NrPrinters > 0 + For i = 0 To NrPrinters - 1 + PName = DYMO_NextPrinter() + Print(#TAB$ + "'" + PName + "'") + If DYMO_IsTwinTurboPrinter(PName) + PrintN(" (TwinTurbo)") + Else + PrintN("") + EndIf + Next +Else + PrintN("NO Printers found") +EndIf + + +PrintN(#LF$) + + +; select a printer +;DYMO_SelectPrinter("MyDYMOprinter") + +; show selected printer +PrintN("Current selected printer: " + DYMO_GetCurrentPrinterName()) +Print(#TAB$ + "Selected tray: ") +Select DYMO_GetCurrentPaperTray() + Case #DYMO_Tray_Unknown + PrintN("Unknown") + Case #DYMO_Tray_Right + PrintN("Right") + Case #DYMO_Tray_Left + PrintN("Left") + Case #DYMO_Tray_Auto + PrintN("Auto") +EndSelect + + +PrintN(#LF$) + + +; Open label file +#LabelFile = #PB_Compiler_FilePath + "Sample_101x54.label" +If DYMO_OpenLabel(#LabelFile) + PrintN("File <" + #LabelFile + "> loaded") +Else + PrintN("Can't load file <" + #LabelFile + ">") +EndIf + +; Open label file from URL +#LabelURL = "file://" + #PB_Compiler_FilePath + "Sample_101x54.label" +If DYMO_OpenLabel(#LabelFile) + PrintN("File from URL <" + #LabelURL + "> loaded") +Else + PrintN("Can't load file from URL <" + #LabelURL + ">") +EndIf + + +; Show Objects in current loaded .label +ShowObjects(#False) ; #False = we want to list all object, not only those who can be changed + + +PrintN(#LF$) + + +; open from memory +Define *Buf, BufSize +*Buf = ?Label_Sample_89x28_Start +BufSize = ?Label_Sample_89x28_End - ?Label_Sample_89x28_Start +If DYMO_OpenMemory(*Buf, BufSize) + PrintN("new label from buffer loaded") +Else + PrintN("Can't load label from buffer") +EndIf + +; Show Objects in current loaded .label +ShowObjects() + + +PrintN(#LF$) + + +; let's set some new values +DYMO_SetField("CODE39", "NEW39") +DYMO_SetField("TXT", "newText") +DYMO_SetField("EAN8", "8888888") +DYMO_SetField("ADR2", "newAddress2") +DYMO_SetAddress("new Address") +DYMO_SetAddress("new new Address2", 2) +DYMO_SetImageFile("LOGO", "Sample_Logo.bmp") + +PrintN("Modified objects") +ShowObjects() ; show new values + + +PrintN(#LF$) + + +; print some labels ... uncomment DYMO_PrintLabel() to send to printer +PrintN("Print one label") +;DYMO_PrintLabel() +PrintN("Print one label using right tray") +;DYMO_PrintLabel(1, #DYMO_Tray_Right) + +; create more modifications and send all together to printer, as one job +DYMO_SetPrintMode(#False) ; print faster but in lower Quality (for labels with barcode or graphic) +DYMO_StartPrintJob() + For i = 1 To 5 + PrintN("Create label nr. " + Str(i)) + DYMO_SetField("CODE39", Str(i)) + DYMO_SetField("TXT", "more Text") + DYMO_SetField("EAN8", Str(i * 8)) + DYMO_SetField("ADR2", "more Address2" + #LF$ + "new line") + DYMO_SetAddress("more Address" + #LF$ + "new line") + DYMO_PrintLabel(1, #DYMO_Tray_Auto, #True) ; Auto switch tray and show print dialog + Next + PrintN("Send job to printer") +;DYMO_StopPrintJob() ; send job to printer, uncomment to send to printer + + +PrintN(#LF$) + + +PrintN("Any key to close ...") +Repeat +Until Inkey() + +; CleanUp +DYMO_Release() + +; Include sample label +DataSection + Label_Sample_89x28_Start: + IncludeBinary "Sample_89x28.label" + Label_Sample_89x28_End: +EndDataSection + +; ExecutableFormat = Console +; CursorPosition = 1 +; FirstLine = 1 +; Folding = - +; CompileSourceDirectory +; EnableCompileCount = 0 +; EnableBuildCount = 0 +; EnableExeConstant +; EnableUnicode \ No newline at end of file diff --git a/LICENSE b/LICENSE index 00d9714..3644ff4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,44 @@ +DYMO4PB +======= + MIT License -Copyright (c) +Copyright (c) <2019> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + + + + +COMatePLUS - Easy access to COM via (OLE) automation. +===================================================== +LICENSE + +DAYLIKE +(Do As You LIKE with it!) + +Nice and simple. + +Needless to say though that I will accept no responsibility for any damage or injury (???) caused by the use (or misuse) of this software. I do not even assert that it is 'fit for purpose' in any way shape or form! + +An acknowledgement within any application making use of this utility is always nice as would an acknowledgement to the original DispHelper software on which COMatePLUS is based (I do not know the name of the DispHelper author!) + +Copyright © 2009 + + http://www.nxSoftware.com + + +With thanks to... + +Thomas Schulz (ts-soft) http://www.realsource.de +Provided code for interfacing with ActiveX controls. +Tested early versions of COMate (which is now COMatePLUS). +Created some of the COMate demo programs. + +Timo Harter (freak) http://freak.purearea.net/ +Provided the know-how and code for connecting EventSinks with COM objects. + +With thanks to Kiffi and mk-soft for their work on the PureDispHelper demo programs which have been translated for use with COMatePLUS. + + diff --git a/README.md b/README.md index 351416f..b4ac2fb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,45 @@ # DYMO4PB +----- -DYMO-Printer SDK Wrapper for PureBasic \ No newline at end of file + +## overview +Use DYMO Labelwriter with PureBasic. DYMO4PB provides simple access to the DYMO-SDK with COMatePlus: + +* examine available DYMO printers +* open / save label from file +* open / save label from memory +* modify and print loaded labels +* change text / address / barcode / graphic +* smart paste from clipboard / file / string +* create printjobs for faster printing +* manage MRU-Labels (Most Recently Used) +* create DLL + + +----- + + +## what you need +* [DYMO Label Software](dymo.com) (DLS) have to be installed. This Include is created for DLS v.8+ (year 2015+). Maybe it works with lower version, but this is untested. +* COMatePlus - Version 1.2 included (2010-06-09) (different author & license, see COMatePLUS.chm). + +----- + +## example: + +``` +DYMO_Init() ; Use this BEFORE any use of DYMO_*() commands. + +DYMO_OpenLabel("MyLabelFile.label") +DYMO_SetField("TextField", "My Text") +DYMO_SetImageFile("Logo", "MyLogo.bmp") +DYMO_PrintLabel() + +DYMO_Release() +``` + +All functions are described in the include file "DYMO.pbi". + +--- +## create DLL +If you want to use the DLL, simple compile "DYMO_CreateDLL.pb" and include "DYMO_DLL.pbi" \ No newline at end of file diff --git a/Sample_101x54.label b/Sample_101x54.label new file mode 100644 index 0000000..ba04613 --- /dev/null +++ b/Sample_101x54.label @@ -0,0 +1,204 @@ + + + Landscape + Shipping + false + 30323 Shipping + + + + + + CODE128 + + + + Rotation0 + False + True + -1 + False + 128 + Code128Auto + Medium + Bottom + + + None + 0 + Center + + + + + + + CODE39 + + + + Rotation0 + False + True + -1 + False + 39 + Code39 + Medium + Bottom + + + None + 0 + Center + + + + + + + ADR + + + + Rotation0 + False + True + -1 + False + Left + Top + ShrinkToFit + True + False + + + Address + + + + + + + False + AboveAddress + + + + + + + + + TXT + + + + Rotation0 + False + True + -1 + False + Left + Top + ShrinkToFit + True + False + + + TextField + + + + + + + + + + + + ADR2 + + + + Rotation0 + False + True + -1 + False + Left + Top + ShrinkToFit + True + False + + + Address2 + + + + + + + False + AboveAddress + + + + + + + + + EAN13 + + + + Rotation0 + False + False + -1 + False + 123456789012 + Ean13 + Medium + Bottom + + + Full + 0 + Center + + + + + + + FIXEDTEXT + + + + Rotation0 + False + False + -1 + False + Left + Top + ShrinkToFit + True + False + + + FixedText + + + + + + + + + + \ No newline at end of file diff --git a/Sample_89x28.label b/Sample_89x28.label new file mode 100644 index 0000000..ba8b855 --- /dev/null +++ b/Sample_89x28.label @@ -0,0 +1,200 @@ + + + Landscape + Address + false + 30252 Address + + + + + + CODE39 + + + + Rotation0 + False + True + -1 + False + 39 + Code39 + Medium + Bottom + + + None + 0 + Center + + + + + + + TXT + + + + Rotation0 + False + True + -1 + False + Center + Top + ShrinkToFit + True + False + + + TextField + + + + + + + + + + + + EAN8 + + + + Rotation0 + False + True + -1 + False + 1234567 + Ean8 + Medium + Bottom + + + Full + 0 + Center + + + + + + + FixedTXT + + + + Rotation0 + False + False + -1 + False + Center + Top + ShrinkToFit + True + False + + + FixedTextField + + + + + + + + + + + + ADR + + + + Rotation0 + False + True + -1 + False + Center + Middle + ShrinkToFit + True + False + + + Address + + + + + + + False + AboveAddress + + + + + + + + + ADR2 + + + + Rotation0 + False + True + -1 + False + Center + Middle + ShrinkToFit + True + False + + + Address2 + + + + + + + False + AboveAddress + + + + + + + + + LOGO + + + + Rotation0 + False + False + -1 + False + iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAMSURBVBhXY/j//z8ABf4C/qc1gYQAAAAASUVORK5CYIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + Uniform + 0 + + Center + Center + + + + \ No newline at end of file diff --git a/Sample_Logo.bmp b/Sample_Logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..5ac51dd046e5d60d99eb8fbe0f575199b7b95785 GIT binary patch literal 3382 zcmeH{%}xU`41}{12QKg&969v?xbxP$7kFkoj(6J)65@jBs+;)d^VmtNzP(?b2A|8r z7%ySH=DUqYC1U+});qRv@Q(3`2mAfK-@*Mi@V|Zoo1ggN2kmBT@dx3&cSnFRNduOQ z2qKYADP)Y4lP+kx@)T==SqI~Ub^0uNd{sq)->27cMXG?3(#;1D!3D4QJ{r*o)A zd=_U&yd3L#-|^6lyI=5}Mo12Z5!p^#>B1n0g#buJb8X=;!GlXGlT=~O^Rtfxi_aOP zu%CyA`Gbqjh7;L39%7#{wU721-C0JaY86JW`YEb5O#K}S(BpoI`IXT01LJN literal 0 HcmV?d00001