Skip to content
This repository was archived by the owner on Feb 24, 2026. It is now read-only.

Commit 7fc2e02

Browse files
committed
Refactor search context to use unsafe pointers
Switch VMMDLL_MEM_SEARCH_CONTEXT to an unsafe struct and replace IntPtr with void* for the search field. Refactor VmmSearch to use fixed blocks instead of GCHandle for pinning, assigning the pointer directly to the context. Move related logic inside the fixed block and remove unnecessary GCHandle usage. This improves interop safety and performance.
1 parent eecde7d commit 7fc2e02

2 files changed

Lines changed: 40 additions & 39 deletions

File tree

src/VmmSharpEx/Internal/Vmmi.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -886,15 +886,15 @@ public struct VMMDLL_MEM_SEARCH_CONTEXT_SEARCHENTRY
886886
public delegate bool SearchResultCallback(VMMDLL_MEM_SEARCH_CONTEXT ctx, ulong va, uint iSearch);
887887

888888
[StructLayout(LayoutKind.Sequential, Pack = 8)]
889-
public struct VMMDLL_MEM_SEARCH_CONTEXT
889+
public unsafe struct VMMDLL_MEM_SEARCH_CONTEXT
890890
{
891891
public uint dwVersion;
892892
private readonly uint _Filler01;
893893
private readonly uint _Filler02;
894894
public int fAbortRequested;
895895
public uint cMaxResult;
896896
public uint cSearch;
897-
public IntPtr search;
897+
public void* search;
898898
public ulong vaMin;
899899
public ulong vaMax;
900900
public readonly ulong vaCurrent;

src/VmmSharpEx/VmmSearch.cs

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -91,55 +91,56 @@ public static unsafe SearchResult MemSearch(this Vmm vmm,
9191
{
9292
return result; // No search items, return empty result.
9393
}
94-
var hSearches = GCHandle.Alloc(searches, GCHandleType.Pinned);
9594
var context = (Vmmi.VMMDLL_MEM_SEARCH_CONTEXT*)NativeMemory.Alloc((nuint)sizeof(Vmmi.VMMDLL_MEM_SEARCH_CONTEXT));
9695
try
9796
{
98-
Vmmi.SearchResultCallback del = SearchResultCallback; // Prevent delegate from being GC'ed during the call.
99-
*context = new Vmmi.VMMDLL_MEM_SEARCH_CONTEXT
97+
fixed (void* pSearches = searches)
10098
{
101-
dwVersion = VMMDLL_MEM_SEARCH_VERSION,
102-
vaMin = addr_min,
103-
vaMax = addr_max,
104-
cMaxResult = cMaxResult,
105-
ReadFlags = (uint)readFlags,
106-
pfnResultOptCB = Marshal.GetFunctionPointerForDelegate(del)
107-
};
108-
context->cSearch = (uint)searches.Length;
109-
context->search = hSearches.AddrOfPinnedObject();
110-
var ctReg = ct.Register(() =>
111-
{
112-
context->fAbortRequested = 1;
113-
});
114-
try
115-
{
116-
result.IsSuccess = Vmmi.VMMDLL_MemSearch(vmm, pid, context, IntPtr.Zero, IntPtr.Zero);
117-
}
118-
finally
119-
{
120-
// IMPORTANT: Ensure we unregister the cancellation token callback before the context is freed.
121-
// This will block (WaitForCallbackIfNecessary) until the callback is completed (if it is already in progress).
122-
ctReg.Dispose();
123-
}
99+
Vmmi.SearchResultCallback del = SearchResultCallback; // Prevent delegate from being GC'ed during the call.
100+
*context = new Vmmi.VMMDLL_MEM_SEARCH_CONTEXT
101+
{
102+
dwVersion = VMMDLL_MEM_SEARCH_VERSION,
103+
vaMin = addr_min,
104+
vaMax = addr_max,
105+
cMaxResult = cMaxResult,
106+
ReadFlags = (uint)readFlags,
107+
pfnResultOptCB = Marshal.GetFunctionPointerForDelegate(del),
108+
cSearch = (uint)searches.Length,
109+
search = pSearches
110+
};
111+
var ctReg = ct.Register(() =>
112+
{
113+
context->fAbortRequested = 1;
114+
});
115+
try
116+
{
117+
result.IsSuccess = Vmmi.VMMDLL_MemSearch(vmm, pid, context, IntPtr.Zero, IntPtr.Zero);
118+
}
119+
finally
120+
{
121+
// IMPORTANT: Ensure we unregister the cancellation token callback before the context is freed.
122+
// This will block (WaitForCallbackIfNecessary) until the callback is completed (if it is already in progress).
123+
ctReg.Dispose();
124+
}
124125

125-
ct.ThrowIfCancellationRequested();
126-
return result;
126+
ct.ThrowIfCancellationRequested();
127+
return result;
127128

128-
bool SearchResultCallback(Vmmi.VMMDLL_MEM_SEARCH_CONTEXT ctx, ulong va, uint iSearch)
129-
{
130-
var e = new SearchResult.Entry
129+
bool SearchResultCallback(Vmmi.VMMDLL_MEM_SEARCH_CONTEXT ctx, ulong va, uint iSearch)
131130
{
132-
Address = va,
133-
SearchTermId = iSearch
134-
};
135-
result._results.Add(e);
136-
return result._results.Count < ctx.cMaxResult;
131+
var e = new SearchResult.Entry
132+
{
133+
Address = va,
134+
SearchTermId = iSearch
135+
};
136+
result._results.Add(e);
137+
return result._results.Count < ctx.cMaxResult;
138+
}
137139
}
138140
}
139141
finally
140142
{
141143
NativeMemory.Free(context);
142-
hSearches.Free();
143144
}
144145
}
145146

0 commit comments

Comments
 (0)