### Start Plugin Execution in WinObjEx64 (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt The StartPlugin callback is invoked when a user activates the plugin from the WinObjEx64 menu. It handles parameter validation, initializes a plugin-specific heap, and launches a worker thread for the plugin's main logic. It returns STATUS_SUCCESS on successful startup or an error status if initialization fails, also notifying WinObjEx64 of the plugin's state change. ```c /* * StartPlugin - Run plugin code in dedicated thread. * Parameters: * ParamBlock - Plugin parameters from WinObjEx64 * Returns: * STATUS_SUCCESS - Plugin started successfully * STATUS_UNSUCCESSFUL - Failed to start */ NTSTATUS CALLBACK StartPlugin( _In_ PWINOBJEX_PARAM_BLOCK ParamBlock ) { DWORD threadId; NTSTATUS status; WINOBJEX_PLUGIN_STATE state = PluginInitialization; if (ParamBlock == NULL) { return STATUS_INVALID_PARAMETER; } // Store parameters for later use RtlCopyMemory(&g_paramBlock, ParamBlock, sizeof(WINOBJEX_PARAM_BLOCK)); InterlockedExchange((PLONG)&g_pluginState, PLUGIN_RUNNING); // Create plugin heap for memory allocations g_pluginHeap = HeapCreate(0, 0, 0); if (g_pluginHeap == NULL) { return STATUS_MEMORY_NOT_ALLOCATED; } HeapSetInformation(g_pluginHeap, HeapEnableTerminationOnCorruption, NULL, 0); // Launch worker thread for plugin UI/logic g_threadHandle = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)PluginThread, NULL, 0, &threadId); if (g_threadHandle) { status = STATUS_SUCCESS; state = PluginRunning; } else { status = STATUS_UNSUCCESSFUL; state = PluginError; HeapDestroy(g_pluginHeap); g_pluginHeap = NULL; } // Notify WinObjEx64 of state change if (g_plugin && g_plugin->StateChangeCallback) { g_plugin->StateChangeCallback(g_plugin, state, NULL); } return status; } ``` -------------------------------- ### Start Context Plugin to Open and Map Section Object (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt The StartPlugin callback for context plugins opens and maps a Section object using the provided callback function. It handles potential errors during object opening and mapping, displaying messages to the user. Dependencies include winobjex parameter blocks and memory mapping functions. ```c /* * StartPlugin for context plugin - opens and maps section object. */ NTSTATUS CALLBACK StartPlugin( _In_ PWINOBJEX_PARAM_BLOCK ParamBlock ) { NTSTATUS status = STATUS_UNSUCCESSFUL; HANDLE sectionHandle = NULL; PVOID sectionAddress = NULL; SIZE_T viewSize = 0; if (ParamBlock == NULL || ParamBlock->OpenNamedObjectByType == NULL) { return STATUS_INVALID_PARAMETER; } // Open the Section object using provided callback // Object directory and name come from ParamBlock->Object status = ParamBlock->OpenNamedObjectByType( §ionHandle, ObjectTypeSection, // Object type index &ParamBlock->Object.Directory, // Directory path &ParamBlock->Object.Name, // Object name SECTION_QUERY | SECTION_MAP_READ); // Desired access if (!NT_SUCCESS(status)) { WCHAR szError[100]; StringCbPrintf(szError, sizeof(szError), TEXT("Could not open section, 0x%08X"), (ULONG)status); MessageBox(ParamBlock->ParentWindow, szError, TEXT("ImageScope"), MB_ICONERROR); return status; } // Map section into memory for analysis status = supMapSection(sectionHandle, §ionAddress, &viewSize); NtClose(sectionHandle); if (!NT_SUCCESS(status)) { if (status == STATUS_NOT_SUPPORTED) { MessageBox(ParamBlock->ParentWindow, TEXT("This section does not represent a mapped image."), TEXT("ImageScope"), MB_ICONINFORMATION); } return status; } // Store mapped address for analysis g_ctx.SectionAddress = sectionAddress; g_ctx.SectionViewSize = viewSize; // Continue with UI creation... return STATUS_SUCCESS; } ``` -------------------------------- ### Add Protocol Information to TreeList (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt An example function demonstrating how to add protocol information to a TreeList control. It utilizes the DumpUnicodeString function to retrieve the protocol name from kernel memory and formats the protocol address as a hex string for display. This function sets up subitems for additional columns in the TreeList. ```c /* * Example: Adding protocol information to TreeList. */ VOID AddProtocolToTreeList( _In_ PNDIS_PROTOCOL_BLOCK_COMPATIBLE ProtoBlock, _In_ ULONG_PTR ProtocolAddress ) { PWCHAR lpProtocolName; TL_SUBITEMS_FIXED subitems; WCHAR szBuffer[32]; // Dump protocol name from kernel lpProtocolName = DumpUnicodeString( (ULONG_PTR)ProtoBlock->Name.Buffer, ProtoBlock->Name.Length, ProtoBlock->Name.MaximumLength, FALSE); if (lpProtocolName) { RtlSecureZeroMemory(&subitems, sizeof(subitems)); // Format address as hex string StringCchPrintf(szBuffer, RTL_NUMBER_OF(szBuffer), TEXT("0x%llX"), ProtocolAddress); // Setup subitems for columns 2 and 3 subitems.Count = 2; subitems.Text[0] = szBuffer; // Column 1: Address subitems.Text[1] = TEXT("NDIS Protocol"); // Column 2: Type TreeListAddItem( g_ctx.TreeList, NULL, // Parent (NULL = root) TVIF_TEXT | TVIF_STATE, TVIS_EXPANDED, TVIS_EXPANDED, lpProtocolName, // Column 0: Name &subitems); supHeapFree(lpProtocolName); } } ``` -------------------------------- ### Initialize and Add Items to ListView (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt Demonstrates how to initialize a ListView control with columns and add items with subitems. It includes functions for setting up columns with DPI awareness and inserting data into the ListView. Dependencies include Windows API functions for ListView manipulation. ```c /* * Initialize ListView with columns. */ VOID InitializeListView( _In_ HWND ListView, _In_ UINT CurrentDPI ) { // Add columns with DPI-aware widths supAddListViewColumn(ListView, 0, 0, 0, I_IMAGENONE, LVCFMT_LEFT, TEXT("Item"), 300, CurrentDPI); supAddListViewColumn(ListView, 1, 1, 1, I_IMAGENONE, LVCFMT_LEFT, TEXT("Value"), 140, CurrentDPI); supAddListViewColumn(ListView, 2, 2, 2, I_IMAGENONE, LVCFMT_LEFT, TEXT("Additional Info"), 300, CurrentDPI); // Enable extended styles ListView_SetExtendedListViewStyle(ListView, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_LABELTIP | LVS_EX_DOUBLEBUFFER); } /* * Add item to ListView with subitems. */ VOID AddListViewItem( _In_ HWND ListView, _In_ LPWSTR lpszItem, _In_ LPWSTR lpszValue, _In_opt_ LPWSTR lpszAdditionalInfo ) { INT lvItemIndex; LVITEM lvItem; RtlSecureZeroMemory(&lvItem, sizeof(lvItem)); lvItem.mask = LVIF_TEXT | LVIF_IMAGE; lvItem.iItem = MAXINT; lvItem.pszText = lpszItem; lvItem.iImage = I_IMAGENONE; lvItemIndex = ListView_InsertItem(ListView, &lvItem); // Set subitem 1 (Value column) lvItem.pszText = lpszValue; lvItem.iSubItem = 1; lvItem.iItem = lvItemIndex; ListView_SetItem(ListView, &lvItem); // Set subitem 2 (Additional Info column) lvItem.pszText = lpszAdditionalInfo ? lpszAdditionalInfo : TEXT(""); lvItem.iSubItem = 2; ListView_SetItem(ListView, &lvItem); } ``` -------------------------------- ### Initialize Plugin for WinObjEx64 (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt The PluginInit function is a mandatory export for all WinObjEx64 plugins. It's called once when the plugin DLL is loaded to register plugin information such as name, author, description, version, and capabilities. It also sets up the StartPlugin and StopPlugin callbacks. The function returns TRUE on success and FALSE on failure, with basic input validation and exception handling. ```c /* * PluginInit - Initialize plugin information for WinObjEx64. * This function is called once when the plugin DLL is loaded. * Returns TRUE on success, FALSE on failure. */ BOOLEAN CALLBACK PluginInit( _Inout_ PWINOBJEX_PLUGIN PluginData ) { // Prevent double initialization if (g_plugin) { return FALSE; } __try { // Validate input if (PluginData == NULL) { return FALSE; } if (PluginData->cbSize < sizeof(WINOBJEX_PLUGIN)) { return FALSE; } if (PluginData->AbiVersion != WINOBJEX_PLUGIN_ABI_VERSION) { return FALSE; } // Set plugin metadata (displayed in WinObjEx64 UI) StringCbCopy(PluginData->Name, sizeof(PluginData->Name), TEXT("My Custom Plugin")); StringCbCopy(PluginData->Authors, sizeof(PluginData->Authors), TEXT("Developer Name")); StringCbCopy(PluginData->Description, sizeof(PluginData->Description), TEXT("Description of what this plugin does.")); // Set version requirements PluginData->RequiredPluginSystemVersion = WOBJ_PLUGIN_SYSTEM_VERSION; PluginData->MajorVersion = 1; PluginData->MinorVersion = 0; // Setup start/stop callbacks PluginData->StartPlugin = (pfnStartPlugin)&StartPlugin; PluginData->StopPlugin = (pfnStopPlugin)&StopPlugin; // Configure capabilities PluginData->Capabilities.u1.NeedAdmin = FALSE; PluginData->Capabilities.u1.SupportWine = TRUE; PluginData->Capabilities.u1.NeedDriver = FALSE; // Set plugin type (DefaultPlugin shows in Plugins menu) PluginData->Type = DefaultPlugin; g_plugin = PluginData; return TRUE; } __except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; } } ``` -------------------------------- ### Initialize Context Plugin for Section Objects (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt Initializes a context plugin for Section objects, making it appear in the right-click menu. It sets plugin metadata, capabilities, and specifies that it supports only Section objects. Dependencies include standard C libraries and winobjex plugin headers. ```c /* * Context plugin initialization for Section objects. * Appears in popup menu when right-clicking Section type objects. */ BOOLEAN CALLBACK PluginInit( _Inout_ PWINOBJEX_PLUGIN PluginData ) { if (g_plugin || PluginData == NULL) { return FALSE; } if (PluginData->AbiVersion != WINOBJEX_PLUGIN_ABI_VERSION) { return FALSE; } StringCbCopy(PluginData->Name, sizeof(PluginData->Name), TEXT("ImageScope")); StringCbCopy(PluginData->Authors, sizeof(PluginData->Authors), TEXT("UG North")); StringCbCopy(PluginData->Description, sizeof(PluginData->Description), TEXT("Display additional information for sections created from PE files.")); PluginData->RequiredPluginSystemVersion = WOBJ_PLUGIN_SYSTEM_VERSION; PluginData->StartPlugin = (pfnStartPlugin)&StartPlugin; PluginData->StopPlugin = (pfnStopPlugin)&StopPlugin; // Enable multiple instances for concurrent viewing PluginData->Capabilities.u1.NeedAdmin = FALSE; PluginData->Capabilities.u1.SupportWine = TRUE; PluginData->Capabilities.u1.NeedDriver = FALSE; PluginData->Capabilities.u1.SupportMultipleInstances = TRUE; PluginData->MajorVersion = 1; PluginData->MinorVersion = 2; // Set as ContextPlugin (appears in right-click menu) PluginData->Type = ContextPlugin; // Configure supported object types // Fill with ObjectTypeNone, then set specific types RtlFillMemory( PluginData->SupportedObjectsIds, sizeof(PluginData->SupportedObjectsIds), ObjectTypeNone); // This plugin handles Section objects only PluginData->SupportedObjectsIds[0] = ObjectTypeSection; g_plugin = PluginData; return TRUE; } ``` -------------------------------- ### Standard Plugin DLL Entry Point (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt Provides the basic DllMain function for Windows DLL plugins. This function serves as the entry point for the DLL and handles process attachment events. It specifically disables thread library calls to improve performance. ```c /* * DllMain - DLL entry point. * Disables thread library calls for performance. */ BOOL WINAPI DllMain( _In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved ) { UNREFERENCED_PARAMETER(lpvReserved); if (fdwReason == DLL_PROCESS_ATTACH) { g_thisDll = hinstDLL; DisableThreadLibraryCalls(hinstDLL); } return TRUE; } ``` -------------------------------- ### Read Kernel Memory with ReadSystemMemoryEx Callback (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt Demonstrates reading kernel memory structures using the ReadSystemMemoryEx callback function. This functionality requires a loaded driver helper and is used for operations like reading protocol blocks and dumping Unicode strings from kernel space. It includes validation for kernel space addresses and checks for the availability of the callback. ```c /* * Read kernel structure using ReadSystemMemoryEx callback. * This requires driver helper to be loaded. */ BOOL ReadProtocolBlock( _In_ ULONG_PTR ProtocolAddress, _Out_ PNDIS_PROTOCOL_BLOCK_COMPATIBLE ProtoBlock ) { ULONG bytesRead = 0; // Validate address is in kernel space if (ProtocolAddress < g_paramBlock.SystemRangeStart) { return FALSE; } // Ensure driver support is available if (g_paramBlock.ReadSystemMemoryEx == NULL) { return FALSE; } // Read kernel structure if (!g_paramBlock.ReadSystemMemoryEx( ProtocolAddress, ProtoBlock, sizeof(NDIS_PROTOCOL_BLOCK_COMPATIBLE), &bytesRead)) { return FALSE; } return (bytesRead == sizeof(NDIS_PROTOCOL_BLOCK_COMPATIBLE)); } /* * Dump UNICODE_STRING from kernel memory. */ PWCHAR DumpUnicodeString( _In_ ULONG_PTR Address, _In_ USHORT Length, _In_ USHORT MaximumLength, _In_ BOOL ReadStructure ) { UNICODE_STRING usString; PWCHAR resultBuffer = NULL; ULONG bytesRead = 0; USHORT allocLength; if (g_paramBlock.ReadSystemMemoryEx == NULL) { return NULL; } if (ReadStructure) { // Read UNICODE_STRING structure first if (!g_paramBlock.ReadSystemMemoryEx( Address, &usString, sizeof(UNICODE_STRING), &bytesRead)) { return NULL; } Length = usString.Length; MaximumLength = usString.MaximumLength; Address = (ULONG_PTR)usString.Buffer; } if (Length == 0 || MaximumLength == 0 || Address == 0) { return NULL; } // Allocate buffer for string content allocLength = (MaximumLength > Length) ? MaximumLength : Length; resultBuffer = (PWCHAR)supHeapAlloc(allocLength + sizeof(WCHAR)); if (resultBuffer == NULL) { return NULL; } // Read string buffer from kernel if (!g_paramBlock.ReadSystemMemoryEx( Address, resultBuffer, Length, &bytesRead)) { supHeapFree(resultBuffer); return NULL; } resultBuffer[Length / sizeof(WCHAR)] = UNICODE_NULL; return resultBuffer; } ``` -------------------------------- ### WINOBJEX_PLUGIN Structure Definition (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt Defines the core structure for WinObjEx64 plugins, specifying metadata, capabilities, and callback pointers. This structure is essential for creating custom plugins that extend WinObjEx64's functionality. ```c typedef struct _WINOBJEX_PLUGIN { ULONG cbSize; // Size of this structure ULONG AbiVersion; // Must be WINOBJEX_PLUGIN_ABI_VERSION (0x0100) union { ULONG Flags; struct { ULONG NeedAdmin : 1; // Requires administrator privileges ULONG NeedDriver : 1; // Requires kernel driver support ULONG SupportWine : 1; // Works on Wine/Wine-Staging ULONG SupportMultipleInstances : 1; // Can run multiple instances ULONG Reserved : 28; } u1; } Capabilities; WINOBJEX_PLUGIN_TYPE Type; // DefaultPlugin or ContextPlugin WINOBJEX_PLUGIN_STATE State; // Current plugin state WORD MajorVersion; // Plugin major version WORD MinorVersion; // Plugin minor version ULONG RequiredPluginSystemVersion; // WOBJ_PLUGIN_SYSTEM_VERSION UCHAR SupportedObjectsIds[255]; // Object types for ContextPlugin WCHAR Name[32]; // Display name in UI WCHAR Authors[32]; // Author information WCHAR Description[128]; // Plugin description pfnStartPlugin StartPlugin; // Start callback pfnStopPlugin StopPlugin; // Stop callback pfnStateChangeCallback StateChangeCallback; // State change notification pfnGuiInitCallback GuiInitCallback; // GUI initialization pfnGuiShutdownCallback GuiShutdownCallback; // GUI cleanup ULONG Reserved[8]; } WINOBJEX_PLUGIN, *PWINOBJEX_PLUGIN; ``` -------------------------------- ### WINOBJEX_PARAM_BLOCK Structure Definition (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt Represents the parameter block passed to a plugin's StartPlugin callback. It contains essential information such as the parent window handle, instance handle, system memory details, and system callbacks provided by WinObjEx64. ```c typedef struct _WINOBJEX_PARAM_BLOCK { ULONG cbSize; // Size of this structure HWND ParentWindow; // Parent window handle HINSTANCE Instance; // WinObjEx64 instance handle ULONG_PTR SystemRangeStart; // Start of kernel address space UINT CurrentDPI; // Current DPI for scaling RTL_OSVERSIONINFOW Version; // Windows version info WINOBJEX_PARAM_OBJECT Object; // Object info (ContextPlugin only) // System callbacks provided by WinObjEx64 pfnReadSystemMemoryEx ReadSystemMemoryEx; // Read kernel memory pfnGetInstructionLength GetInstructionLength; // Disassemble instruction pfnOpenNamedObjectByType OpenNamedObjectByType; // Open named objects ULONG Reserved[8]; } WINOBJEX_PARAM_BLOCK, *PWINOBJEX_PARAM_BLOCK; ``` -------------------------------- ### Copy Text to Clipboard (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt A utility function to copy wide character text to the system clipboard. It handles memory allocation, clipboard opening and closing, and setting the clipboard data. Ensure the input text is null-terminated if required by the application context. ```c /* * Copy text to clipboard. */ VOID supClipboardCopy( _In_ LPWSTR lpText, _In_ SIZE_T cbText ) { LPWSTR lptstrCopy; HGLOBAL hglbCopy = NULL; SIZE_T dwSize; BOOL dataSet = FALSE; if (!OpenClipboard(NULL)) return; __try { EmptyClipboard(); dwSize = cbText + sizeof(UNICODE_NULL); hglbCopy = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, dwSize); if (hglbCopy == NULL) __leave; lptstrCopy = (LPWSTR)GlobalLock(hglbCopy); if (lptstrCopy == NULL) __leave; RtlCopyMemory(lptstrCopy, lpText, cbText); GlobalUnlock(hglbCopy); dataSet = SetClipboardData(CF_UNICODETEXT, hglbCopy) != NULL; if (dataSet) { hglbCopy = NULL; // System owns it now } } __finally { CloseClipboard(); if (hglbCopy != NULL) { GlobalFree(hglbCopy); } } } ``` -------------------------------- ### Copy ListView Item to Clipboard (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt Copies the text of a specific item and subitem from a ListView control to the system clipboard. It retrieves the item's text using `supGetItemText` and then uses `supClipboardCopy` to perform the actual clipboard operation. Returns true on success, false otherwise. ```c /* * Copy selected ListView item value to clipboard. */ BOOL CopyListViewItemToClipboard( _In_ HWND hwndListView, _In_ INT iItem, _In_ INT iSubItem ) { SIZE_T cbText; LPWSTR lpText; if ((iSubItem < 0) || (iItem < 0)) return FALSE; lpText = supGetItemText(hwndListView, iItem, iSubItem, NULL); if (lpText) { cbText = _strlen(lpText) * sizeof(WCHAR); supClipboardCopy(lpText, cbText); supHeapFree(lpText); return TRUE; } return FALSE; } ``` -------------------------------- ### Export ListView to CSV (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt Provides a function to export the contents of a ListView control to a CSV file. It utilizes a helper function `supListViewExportToFile` to handle the file dialog and data writing. The function takes the owner window handle and the ListView handle as input. ```c /* * Export ListView contents to CSV file. */ VOID ExportListViewToCSV( _In_ HWND WindowHandle, _In_ HWND ListView ) { supListViewExportToFile( TEXT("export.csv"), WindowHandle, ListView, TEXT("CSV Files\0*.csv\0\0")); } ``` -------------------------------- ### Add Item to TreeList Control (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt Provides a function to add items to a TreeList control, supporting multiple columns and item states. This utility is part of the Plugin UI Utilities and is used to populate the TreeList with hierarchical data. It takes various parameters to define the item's text, parent, and state. ```c /* * Add item to TreeList control with multiple columns. */ HTREEITEM TreeListAddItem( _In_ HWND TreeList, _In_opt_ HTREEITEM hParent, _In_ UINT mask, _In_ UINT state, _In_ UINT stateMask, _In_opt_ LPWSTR pszText, _In_opt_ PVOID subitems ) { TVINSERTSTRUCT tvitem; PTL_SUBITEMS si = (PTL_SUBITEMS)subitems; RtlSecureZeroMemory(&tvitem, sizeof(tvitem)); tvitem.hParent = hParent; tvitem.item.mask = mask; tvitem.item.state = state; tvitem.item.stateMask = stateMask; tvitem.item.pszText = pszText; tvitem.hInsertAfter = TVI_LAST; return TreeList_InsertTreeItem(TreeList, &tvitem, si); } ``` -------------------------------- ### Object Type Constants Definition (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt Defines common object type identifiers used for context plugins, such as device, driver, process, and thread objects. It also includes special values like `ObjectTypeAnyType` and `ObjectTypeNone` for broader matching or termination. ```c // Common object types for context plugins #define ObjectTypeDevice 0 // \Device objects #define ObjectTypeDriver 1 // Driver objects #define ObjectTypeSection 2 // Section (memory mapped) objects #define ObjectTypePort 3 // ALPC port objects #define ObjectTypeSymbolicLink 4 // Symbolic links #define ObjectTypeKey 5 // Registry key objects #define ObjectTypeEvent 6 // Event synchronization objects #define ObjectTypeJob 7 // Job objects #define ObjectTypeMutant 8 // Mutex objects #define ObjectTypeDirectory 11 // Directory objects #define ObjectTypeProcess 26 // Process objects #define ObjectTypeToken 28 // Token objects #define ObjectTypeThread 30 // Thread objects #define ObjectTypeFltConnPort 36 // Filter connection port #define ObjectTypeMemoryPartition 54 // Memory partition objects // Special values #define ObjectTypeAnyType 0xfe // Match any object type #define ObjectTypeNone 0xff // No object / terminator #define PLUGIN_MAX_SUPPORTED_OBJECT_ID 0xff ``` -------------------------------- ### Stop Plugin Execution and Cleanup in WinObjEx64 (C) Source: https://context7.com/hfiref0x/winobjex64/llms.txt The StopPlugin callback is responsible for gracefully terminating plugin execution and releasing all acquired resources when the plugin is closed or the application exits. It signals the worker thread to stop, waits for its completion with a timeout, and then cleans up the plugin's heap and handles. Finally, it notifies WinObjEx64 about the plugin's stopped state. ```c /* * StopPlugin - Stop plugin execution and cleanup resources. */ void CALLBACK StopPlugin(VOID) { if (g_threadHandle) { // Signal stop to worker thread InterlockedExchange((PLONG)&g_pluginState, PLUGIN_STOP); // Wait for graceful shutdown with timeout if (WaitForSingleObject(g_threadHandle, 1000) == WAIT_TIMEOUT) { TerminateThread(g_threadHandle, 0); } CloseHandle(g_threadHandle); g_threadHandle = NULL; // Cleanup heap if (g_pluginHeap) { HeapDestroy(g_pluginHeap); g_pluginHeap = NULL; } // Notify state change if (g_plugin && g_plugin->StateChangeCallback) { g_plugin->StateChangeCallback(g_plugin, PluginStopped, NULL); } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.