Numeric1 Posted Sunday at 10:56 PM Posted Sunday at 10:56 PM I’m thrilled to introduce my IStream UDF, a sophisticated library designed to handle the COM IStream interface in AutoIt. This UDF enables management of data streams, whether from files, memory, or other sources, leveraging Windows IStream APIs. It provides a reliable solution for reading, writing, and administering streams in your AutoIt scripts. Whether you need to process large files, manipulate in-memory data, or handle transactional streams, this UDF is crafted to be versatile, well-documented, and user-friendly.Key Features Full Implementation of the IStream Interface: Supports all methods of the IStream interface (Read, Write, Seek, SetSize, CopyTo, Commit, Revert, LockRegion, UnlockRegion, Stat, Clone). Support for File and Memory Streams: Create streams from files using _SHCreateStreamOnFileEx or from in-memory data with _StreamCreateFromData, _SHCreateMemStream, and _StreamCreateFromDataOnHGlobal. Advanced Error Handling: Includes a detailed HRESULT error table ($tagIStreamErrorTable) and a _IStream_GetErrorInfo function for clear, understandable error messages. Utility Functions: Functions like _StreamGetSize, _StreamGetName, _StreamGetType, and _StreamStatDisplay simplify access to stream metadata. Comprehensive Documentation: Each function comes with standard UDF-format documentation, including syntax, parameters, return values, remarks, MSDN links, and practical examples. Compatibility: Works with AutoIt 3.3+ and relies on standard libraries (AutoItObject, WinAPI, Memory, Date). Use Cases Reading and writing large files without loading their entire content into memory. Handling in-memory binary data for applications such as network stream processing or serialized data manipulation. Supporting transactional streams for secure operations (e.g., via StgCreateDocfile). Integration with other COM interfaces requiring IStream. you need: AutoItObject.au3 Example: copy data between streams expandcollapse popup#include "IStream.au3" ; Example demonstrating the use of _StreamCopyToEx to copy data between streams Func Example_StreamCopyToEx() ; Create a source stream with the content "Strong" using _StreamCreateFromDataOnHGlobal ConsoleWrite("Creating source stream with 'Strong'..." & @CRLF) Local $iSrcSize,$aError Local $oSrcStream = _StreamCreateFromDataOnHGlobal("Strong", $iSrcSize, True) If @error Or Not IsObj($oSrcStream) Then ; Handle errors by displaying the HRESULT code and details from $tagIStreamErrorTable ConsoleWrite("Error: Failed to create source stream. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) $aError = _IStream_GetErrorInfo(@extended) If IsArray($aError) Then ConsoleWrite("Name: " & $aError[0] & @CRLF) ConsoleWrite("Description: " & $aError[1] & @CRLF) ConsoleWrite("Affected methods: " & $aError[2] & @CRLF) EndIf Return EndIf ConsoleWrite("Source stream created, size: " & $iSrcSize & " bytes" & @CRLF) ; Create a destination stream with the content "AutoIt is " using _StreamCreateFromDataOnHGlobal ConsoleWrite("Creating destination stream with 'AutoIt is '..." & @CRLF) Local $iDestSize Local $oDestStream = _StreamCreateFromDataOnHGlobal("AutoIt is ", $iDestSize, True) If @error Or Not IsObj($oDestStream) Then ; Handle errors for destination stream creation ConsoleWrite("Error: Failed to create destination stream. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) $aError = _IStream_GetErrorInfo(@extended) If IsArray($aError) Then ConsoleWrite("Name: " & $aError[0] & @CRLF) ConsoleWrite("Description: " & $aError[1] & @CRLF) ConsoleWrite("Affected methods: " & $aError[2] & @CRLF) EndIf ; Release the source stream and COM resources before exiting _StreamRelease($oSrcStream) Return EndIf ConsoleWrite("Destination stream created, size: " & $iDestSize & " bytes" & @CRLF) ; Copy the content from the source stream to the destination stream using _StreamCopyToEx ConsoleWrite("Copying 'Strong' to destination stream..." & @CRLF) Local $iBytesRead, $iBytesWritten If Not _StreamCopyToEx($oSrcStream, $oDestStream, $iSrcSize, $iBytesRead, $iBytesWritten) Then ; Handle errors during the copy operation ConsoleWrite("Error: _StreamCopyToEx failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) $aError = _IStream_GetErrorInfo(@extended) If IsArray($aError) Then ConsoleWrite("Name: " & $aError[0] & @CRLF) ConsoleWrite("Description: " & $aError[1] & @CRLF) ConsoleWrite("Affected methods: " & $aError[2] & @CRLF) EndIf ; Release both streams and COM resources before exiting _StreamRelease($oDestStream) _StreamRelease($oSrcStream) Return EndIf ConsoleWrite("Copied " & $iBytesRead & " bytes read, " & $iBytesWritten & " bytes written." & @CRLF) ; Read and display the content of the destination stream ConsoleWrite("Reading destination stream content..." & @CRLF) Local $iNewDestSize = _StreamGetSize($oDestStream) If @error Then ; Handle errors when retrieving the destination stream size ConsoleWrite("Error: Failed to get destination stream size. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) $aError = _IStream_GetErrorInfo(@extended) If IsArray($aError) Then ConsoleWrite("Name: " & $aError[0] & @CRLF) ConsoleWrite("Description: " & $aError[1] & @CRLF) ConsoleWrite("Affected methods: " & $aError[2] & @CRLF) EndIf ; Release both streams and COM resources before exiting _StreamRelease($oDestStream) _StreamRelease($oSrcStream) Return EndIf ConsoleWrite("Destination stream size after copy: " & $iNewDestSize & " bytes" & @CRLF) ; Position the stream pointer at the beginning for reading Local $pDestMem, $iDestRead _StreamSeek($oDestStream, 0, $STREAM_SEEK_SET) If @error Then ; Handle errors when seeking in the destination stream ConsoleWrite("Error: Failed to seek destination stream. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) $aError = _IStream_GetErrorInfo(@extended) If IsArray($aError) Then ConsoleWrite("Name: " & $aError[0] & @CRLF) ConsoleWrite("Description: " & $aError[1] & @CRLF) ConsoleWrite("Affected methods: " & $aError[2] & @CRLF) EndIf _StreamRelease($oDestStream) _StreamRelease($oSrcStream) Return EndIf ; Read the content of the destination stream _StreamRead($oDestStream, $iNewDestSize, $pDestMem, $iDestRead) If @error Then ; Handle errors when reading the destination stream ConsoleWrite("Error: Failed to read destination stream. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) $aError = _IStream_GetErrorInfo(@extended) If IsArray($aError) Then ConsoleWrite("Name: " & $aError[0] & @CRLF) ConsoleWrite("Description: " & $aError[1] & @CRLF) ConsoleWrite("Affected methods: " & $aError[2] & @CRLF) EndIf ; Free the memory buffer if allocated, then release streams and COM resources If $pDestMem Then _MemGlobalFree($pDestMem) _StreamRelease($oDestStream) _StreamRelease($oSrcStream) _WinAPI_CoUninitialize() Return EndIf ; Convert the read data to a string and display it Local $bufSize Local $bDestData = _WinAPI_GetBufferData($pDestMem, $bufSize) ConsoleWrite("Destination stream content: " & BinaryToString($bDestData, 4) & @CRLF) ; Free the memory buffer If $pDestMem Then _MemGlobalFree($pDestMem) ; Release both streams to prevent memory leaks _StreamRelease($oDestStream) _StreamRelease($oSrcStream) ConsoleWrite("COM uninitialized, resources freed." & @CRLF) EndFunc ;==>Example_StreamCopyToEx ; Run the example Example_StreamCopyToEx() example demonstrating multiple IStream interface methods expandcollapse popup#include "IStream.au3" ; Example demonstrating multiple IStream interface methods Func Example_IStream() ; Initialize the COM object model (required for COM API calls) _WinAPI_CoInitialize() ConsoleWrite("=== Creating Stream with SHCreateMemStream ===" & @CRLF) ; Create a memory stream with initial content "Hello, IStream UDF!" Local $sData = "Hello, IStream UDF!" Local $iSize = 0 Local $oStream = _StreamCreateFromData($sData, $iSize) If @error Then ; Handle stream creation error and display details ConsoleWrite("Error: Failed to create stream. @error = " & @error & @CRLF) _WinAPI_CoUninitialize() Return EndIf ConsoleWrite("Stream created successfully. Size: " & $iSize & " bytes" & @CRLF) ; Test IUnknown::QueryInterface to verify the IStream interface ConsoleWrite("Testing QueryInterface..." & @CRLF) Local $IID_IStream = "{0000000C-0000-0000-C000-000000000046}" Local $pQueriedStream = _StreamQueryInterface($oStream, $IID_IStream) If @error Then ; Handle QueryInterface error and release resources ConsoleWrite("Error: QueryInterface failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf ConsoleWrite("QueryInterface succeeded." & @CRLF) ; Release the queried interface to prevent memory leaks DllCall("ole32.dll", "ulong", "Release", "ptr", $pQueriedStream) ; Test IStream::Write by appending additional data ConsoleWrite("Testing Write..." & @CRLF) Local $sNewData = " Additional data." ; 16 characters Local $iNewSize = 0 Local $pMemory = _StreamCreateMemoryBuffer($sNewData, $iNewSize) If @error Then ; Handle memory buffer creation error ConsoleWrite("Error: Failed to create memory buffer. @error = " & @error & @CRLF) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf Local $iWrittenSize = 0 ; Set the stream size to accommodate new data If Not _StreamSetSize($oStream, $iSize + $iNewSize) Then ConsoleWrite("Error: SetSize failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) _WinAPI_FreeMemory($pMemory) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf ; Move the stream pointer to the end for appending If Not _StreamSeek($oStream, $iSize, $STREAM_SEEK_SET) Then ConsoleWrite("Error: Seek failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) _WinAPI_FreeMemory($pMemory) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf ; Write the new data to the stream If Not _StreamWrite($oStream, $pMemory, $iNewSize, $iWrittenSize) Then ConsoleWrite("Error: Write failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) _WinAPI_FreeMemory($pMemory) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf ConsoleWrite("Wrote " & $iWrittenSize & " bytes." & @CRLF) ; Free the memory buffer _WinAPI_FreeMemory($pMemory) ; Test IStream::Seek to move the pointer to the beginning ConsoleWrite("Testing Seek..." & @CRLF) Local $iNewPosition = _StreamSeek($oStream, 0, $STREAM_SEEK_SET) If @error Then ConsoleWrite("Error: Seek failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf ConsoleWrite("Stream pointer moved to: " & $iNewPosition & @CRLF) ; Test IStream::Read to retrieve the entire stream content ConsoleWrite("Testing Read..." & @CRLF) Local $pMemoryRead = 0, $iReadSize = 0 If Not _StreamRead($oStream, $iSize + $iNewSize, $pMemoryRead, $iReadSize) Then ConsoleWrite("Error: Read failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) _WinAPI_FreeMemory($pMemoryRead) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf Local $bData = _WinAPI_GetBufferData($pMemoryRead, $iReadSize) ConsoleWrite("Read " & $iReadSize & " bytes: " & BinaryToString($bData) & @CRLF) _WinAPI_FreeMemory($pMemoryRead) ; Verify that the read data matches the expected content If $iReadSize <> $iSize + $iNewSize Or BinaryToString($bData) <> $sData & $sNewData Then ConsoleWrite("Error: Read data does not match expected: " & $sData & $sNewData & @CRLF) EndIf ; Test IStream::CopyTo by copying the stream to a new destination stream ConsoleWrite("Testing CopyTo..." & @CRLF) ; Create a destination stream Local $pDestStream = _WinAPI_CreateStreamOnHGlobal(0, True) If Not $pDestStream Then ConsoleWrite("Error: Failed to create destination stream." & @CRLF) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf ; Move the source stream pointer to the beginning $iNewPosition = _StreamSeek($oStream, 0, $STREAM_SEEK_SET) If @error Then ConsoleWrite("Error: Seek failed on source stream. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) DllCall("ole32.dll", "ulong", "Release", "ptr", $pDestStream) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf ; Copy the content to the destination stream Local $iBytesRead = 0, $iBytesWritten = 0 If Not _StreamCopyTo($oStream, $pDestStream, $iSize + $iNewSize, $iBytesRead, $iBytesWritten) Then ConsoleWrite("Error: CopyTo failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) DllCall("ole32.dll", "ulong", "Release", "ptr", $pDestStream) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf ConsoleWrite("Copied " & $iBytesRead & " bytes read, " & $iBytesWritten & " bytes written." & @CRLF) ; Create an IStream object from the destination stream pointer Local $oDestStream = _AutoItObject_WrapperCreate($pDestStream, $tagIStream) If @error Then ConsoleWrite("Error: Failed to create destination stream object. @error = " & @error & @CRLF) DllCall("ole32.dll", "ulong", "Release", "ptr", $pDestStream) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf ; Read and verify the destination stream content _StreamSeek($oDestStream, 0, $STREAM_SEEK_SET) Local $pDestMemory, $iDestReadSize If Not _StreamRead($oDestStream, $iSize + $iNewSize, $pDestMemory, $iDestReadSize) Then ConsoleWrite("Error: Reading destination stream failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) _WinAPI_FreeMemory($pDestMemory) _StreamRelease($oDestStream) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf Local $bDestData = _WinAPI_GetBufferData($pDestMemory, $iDestReadSize) ConsoleWrite("Destination stream content: " & BinaryToString($bDestData, $SB_UTF8) & @CRLF) _WinAPI_FreeMemory($pDestMemory) ; Verify that the copied data matches the expected content ; Test IStream::Commit ConsoleWrite("Testing Commit..." & @CRLF) If Not _StreamCommit($oDestStream, $STGC_DEFAULT) Then ConsoleWrite("Error: Commit failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) Else ConsoleWrite("Commit succeeded." & @CRLF) EndIf ; Test IStream::Revert ConsoleWrite("Testing Revert..." & @CRLF) If Not _StreamRevert($oDestStream) Then ; Note that Revert may not be supported by memory streams ConsoleWrite("Note: Revert may not be supported. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) Else ConsoleWrite("Revert succeeded (unexpected for memory stream)." & @CRLF) EndIf ; Test IStream::LockRegion and UnlockRegion ConsoleWrite("Testing LockRegion..." & @CRLF) If Not _StreamLockRegion($oStream, 0, 10, 0) Then ; Note that LockRegion may not be supported by memory streams ConsoleWrite("Note: LockRegion may not be supported. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) __IStreamErrorInfo(@extended) Else ConsoleWrite("LockRegion succeeded." & @CRLF) ConsoleWrite("Testing UnlockRegion..." & @CRLF) If Not _StreamUnlockRegion($oStream, 0, 10, 0) Then ConsoleWrite("Error: UnlockRegion failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) Else ConsoleWrite("UnlockRegion succeeded." & @CRLF) EndIf EndIf ; Test IStream::Stat to retrieve stream metadata ConsoleWrite("Testing GetStat..." & @CRLF) Local $pStatFlag = 0 If Not _StreamGetStat($oStream, $pStatFlag) Then ConsoleWrite("Error: GetStat failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) _StreamRelease($oDestStream) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf ConsoleWrite("Displaying stream metadata:" & @CRLF) _StreamStatDisplay($pStatFlag) _WinAPI_CoTaskMemFree($pStatFlag) ; Test IStream::GetType and GetName ConsoleWrite("Testing GetType and GetName..." & @CRLF) Local $sType = _StreamGetType($oStream) If @error Then ConsoleWrite("Error: GetType failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) Else ConsoleWrite("Stream type: " & $sType & @CRLF) EndIf Local $sName = _StreamGetName($oStream) If @error Then ConsoleWrite("Error: GetName failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) Else ConsoleWrite("Stream name: " & $sName & @CRLF) EndIf ; Test IStream::Clone ConsoleWrite("Testing Clone..." & @CRLF) Local $pCloned Local $oCloneStream = _StreamClone($oStream, $pCloned) If @error Then ConsoleWrite("Error: Clone failed. @error = " & @error & ", @extended = 0x" & Hex(@extended, 8) & @CRLF) _StreamRelease($oDestStream) _StreamRelease($oStream) _WinAPI_CoUninitialize() Return EndIf ConsoleWrite("Clone stream created successfully." & @CRLF) _StreamRelease($oCloneStream) DllCall("ole32.dll", "ulong", "Release", "ptr", $pCloned) ; Clean up all resources _StreamRelease($oDestStream) _StreamRelease($oStream) _WinAPI_CoUninitialize() ConsoleWrite("All streams released and COM uninitialized." & @CRLF) EndFunc ;==>Example_IStream ; Run the example Example_IStream() The help file is included with the UDF IStream.zip KaFu, argumentum and WildByDesign 2 1
argumentum Posted Sunday at 11:49 PM Posted Sunday at 11:49 PM Nice !. The $tagIStreamErrorTable is in French. I don't mind because am a polyglot ( via google ) but in English would be better Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting.
Numeric1 Posted yesterday at 02:16 AM Author Posted yesterday at 02:16 AM 2 hours ago, argumentum said: Nice !. The $tagIStreamErrorTable is in French. I don't mind because am a polyglot ( via google ) but in English would be better Shall we do a copy-paste? 😁 ; #INTERNAL_USE_ONLY# =========================================================================================================== ; Name ..........: $tagIStreamErrorTable ; Description ...: 2D array containing possible HRESULT error codes for the IStream interface, along with their symbolic names and descriptions. ; Fields ........: HRESULT (hex) | Symbolic name | Description | Affected methods ; Author ........: Numeric1 ; Modified ......: 2025-07-27 ; Remarks .......: HRESULT codes starting with 0x8003 are specific to storage errors (STG_E_*). Use this array to translate HRESULT codes returned by IStream methods. ; Related .......: IStream UDF ; =============================================================================================================================== Global Const $tagIStreamErrorTable = [ _ ["0x80030001", "STG_E_INVALIDFUNCTION", "Function invalid for this stream type (e.g., Revert on a non-transactional stream).", "Revert, Commit, LockRegion, UnlockRegion"], _ ["0x80030002", "STG_E_FILENOTFOUND", "The specified file or stream does not exist.", "Stat"], _ ["0x80030008", "STG_E_TOOMANYOPENFILES", "Too many files or streams are open.", "Open, Create"], _ ["0x8003001D", "STG_E_INVALIDPOINTER", "Invalid pointer passed to the method.", "Read, Write, Seek, SetSize, CopyTo, Stat, Clone"], _ ["0x80030020", "STG_E_LOCKVIOLATION", "Lock violation (e.g., accessing a locked region).", "Read, Write, LockRegion, UnlockRegion"], _ ["0x80030021", "STG_E_FILEALREADYEXISTS", "The stream or file already exists.", "Create"], _ ["0x80030050", "STG_E_INVALIDNAME", "Invalid stream name.", "Stat"], _ ["0x80030057", "STG_E_INVALIDPARAMETER", "Invalid parameter passed to the method.", "Seek, CopyTo, Commit, LockRegion, UnlockRegion"], _ ["0x80030070", "STG_E_MEDIUMFULL", "The storage medium is full.", "Write, SetSize, CopyTo"], _ ["0x800300F0", "STG_E_READFAULT", "Error reading from the stream.", "Read, CopyTo"], _ ["0x800300FA", "STG_E_WRITEFAULT", "Error writing to the stream.", "Write, CopyTo, SetSize"], _ ["0x80030102", "STG_E_REVERTED", "The stream was reverted and is no longer valid.", "Read, Write, Seek"], _ ["0x80030103", "STG_E_NOTCURRENT", "The stream has been modified since the last operation.", "Commit, Revert"], _ ["0x80030104", "STG_E_CANTSAVE", "Unable to save changes to the stream.", "Commit"], _ ["0x8007000E", "E_OUTOFMEMORY", "Insufficient memory to perform the operation.", "Read, Write, SetSize, CopyTo, Clone"], _ ["0x80070057", "E_INVALIDARG", "One or more arguments are invalid.", "Read, Write, Seek, SetSize, CopyTo, Commit, LockRegion, UnlockRegion, Stat, Clone"], _ ["0x80004001", "E_NOTIMPL", "The method is not implemented for this stream type (e.g., LockRegion on a memory stream).", "LockRegion, UnlockRegion"], _ ["0x80004005", "E_FAIL", "Unspecified operation failure.", "All methods"], _ ["0x80030006", "STG_E_INSUFFICIENTMEMORY", "Insufficient memory for the operation (similar to E_OUTOFMEMORY).", "Read, Write, SetSize, CopyTo, Clone"] _ ] thanks argumentum 1
Numeric1 Posted 2 hours ago Author Posted 2 hours ago 🔧 Proposal: COM Interface Validation via QueryInterface (_IsObjType, _IsStream) Hi everyone 👋, In the IStream.au3 UDF I recently shared, some internal functions rely on IsObj() to validate the COM objects passed as parameters. While convenient, this check does not guarantee that the object truly implements the expected COM interface (e.g., IStream). I’m suggesting a more robust alternative that directly uses the COM mechanism QueryInterface() to verify if a given object supports a specific interface via its Interface Identifier (IID). ✅ Goal - Ensure a COM object actually implements the required interface (IStream, IMarshal, IPersistStream, etc.). - Avoid runtime crashes when calling methods on unsupported interfaces. - Follow COM best practices: validate interface compatibility through QueryInterface() rather than relying only on IsObj(). 🔍 Difference: IsObj() vs _IsObjType() ; Comparison Table: IsObj() vs _IsObjType() ; +----------------+-------------------+--------------+---------------------------------------------+ ; | Check Type | Reliability | Performance | Comment | ; +----------------+-------------------+--------------+---------------------------------------------+ ; | IsObj() | Basic (any object)| Fast | Does NOT verify interface type | ; | _IsObjType() | Strong (uses QI) | Slower | Uses QueryInterface for real type checking | ; +----------------+-------------------+--------------+---------------------------------------------+ ⚠️ Performance in loops Using QueryInterface() internally, _IsObjType() is naturally more expensive than IsObj(): - It converts the IID to a binary structure - Calls the COM method QueryInterface - Releases the interface pointer safely to avoid memory leaks This performance impact is usually negligible in typical use. However, within loops (e.g. enumerating files or objects via IEnumSTATSTG, IEnumUnknown), repeatedly calling _IsObjType() could slow down execution. 💡 In such cases: - Perform the check once before the loop - Or cache the result locally 🔧 Main Function: _IsObjType() Func _IsObjType(ByRef $oObject, $sIID, $blTag = True) If Not IsObj($oObject) Then Return SetError(1, 0, 0) If Not IsString($sIID) Or $sIID = "" Then Return SetError(2, 0, 0) Local $tRIID = _WinAPI_GUIDFromString($sIID) If Not IsDllStruct($tRIID) Then Return SetError(3, 0, 0) Local $aCall = ($blTag) ? _ $oObject.QueryInterface("hresult", "ptr", DllStructGetPtr($tRIID), "ptr*", 0) : _ $oObject.QueryInterface(DllStructGetPtr($tRIID), 0) If @error Then If Not IsArray($aCall) Then Return SetError(4, @error, 0) If $aCall[0] <> 0 Then Return SetError(5, $aCall[0], 0) EndIf Local $pInterface = $aCall[2] If $pInterface Then DllCall("ole32.dll", "ulong", "Release", "ptr", $pInterface) Return 1 EndIf Return SetError(6, 0, 0) EndFunc 🔁 _IsStream() simplified example Func _IsStream(ByRef $oObject) Return _IsObjType($oObject, "{0000000C-0000-0000-C000-000000000046}") EndFunc --- 🔗 Suggested Integration in UDF I recommend using these functions instead of IsObj() in your COM wrappers (especially those expecting IStream or other specific interfaces). For example, replace: If Not IsObj($oStream) Then Return SetError(1, 0, 0) with: If Not _IsStream($oStream) Then Return SetError(1, 0, 0) 📎 References - IUnknown::QueryInterface (MSDN) - IStream interface (MSDN) What do you think? Should I integrate these improvements into the next version of the IStream.au3 UDF? All feedback and suggestions are welcome! 🙏
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now