(lib)mpg123 use of function mpg123_index in C# - c#

I'm using mpg123 inside my project to decode mp3. I spoke with the developer (Thomas Orgis) about a performance issue when seeking and he had a great idea: Scan the file and afterwards set the scanned index to the playback handle.
So I want to use mpg123_index and mpg123_set_index inside my C# project and use a wrapper around libmpg123.
The wrapper is not self written, I also contacted the developer, but he seems to be unavailable. So maybe someone has knowledge of pointer programming, I also did some things myself, but currently I only get a AccessViolationException when calling the method.
Here some Code:
Wrapper specification (maybe this is wrong?!):
[DllImport(Mpg123Dll)]public static extern int mpg123_index(IntPtr mh, IntPtr offsets, IntPtr step, IntPtr fill);
Specification on Website (C):
https://www.mpg123.de/api/group__mpg123__seek.shtml#gae1d174ac632ec72df7dead94c04865fb
MPG123_EXPORT int mpg123_index ( mpg123_handle * mh, off_t **
offsets, off_t * step, size_t * fill )
Give access to the frame index table that is managed for seeking. You
are asked not to modify the values... Use mpg123_set_index to set the
seek index
Parameters
mh handle
offsets pointer to the index array
step one index byte offset advances this many MPEG frames
fill number of recorded index offsets; size of the array
Returns
MPG123_OK on success
My try to use the function in C#:
IntPtr pIndex = IntPtr.Zero;
IntPtr pFill = IntPtr.Zero;
IntPtr pStep = IntPtr.Zero;
if (MPGImport.mpg123_index(this.mp3Handle,pIndex,pStep,pFill) != (int)MPGImport.mpg123_errors.MPG123_OK))
{
log.error("Failed!");
}
So, has anyone an idea, how to use the function properly on C# side? From the author of mpg123 I just got the information, that the pIndex will be a pointer to the internal index. So this pointer will be changed by this function.
Thanks for your help.
Sincerely
Sven
Edit:
Now the following code almost works:
[DllImport(Mpg123Dll)]public unsafe static extern int mpg123_index(IntPtr mh, long **offsets, long *step, ulong *fill);
[DllImport(Mpg123Dll)]public unsafe static extern int mpg123_set_index(IntPtr mh, long* offsets, long step, ulong fill);
public static Boolean CopyIndex(IntPtr _sourceHandle,IntPtr _destinationHandle)
{
Boolean copiedIndex = false;
unsafe
{
long* offsets = null;
long step = 0;
ulong fill = 0;
int result = MPGImport.mpg123_index(_sourceHandle, &offsets, &step, &fill);
if (result == (int)MPGImport.mpg123_errors.MPG123_OK)
{
result = MPGImport.mpg123_set_index(_destinationHandle, offsets, step, fill);
if (result == (int)mpg123_errors.MPG123_OK)
{
copiedIndex = true;
}
}
}
return copiedIndex;
}
On result = MPGImport.mpg123_set_index(_destinationHandle, offsets, step, fill); the result is -1, which is MPG123_ERR = -1, /**< Generic Error */.

Working code:
[DllImport(Mpg123Dll)]public unsafe static extern int mpg123_index(IntPtr mh, long **offsets, long *step, ulong *fill);
[DllImport(Mpg123Dll)]public unsafe static extern int mpg123_set_index(IntPtr mh, long* offsets, long step, ulong fill);
public static Boolean CopyIndex(IntPtr _sourceHandle,IntPtr _destinationHandle)
{
Boolean copiedIndex = false;
unsafe
{
long* offsets = null;
long step = 0;
ulong fill = 0;
int result = MPGImport.mpg123_index(_sourceHandle, &offsets, &step, &fill);
if (result == (int)MPGImport.mpg123_errors.MPG123_OK)
{
result = MPGImport.mpg123_set_index(_destinationHandle, offsets, step, fill);
if (result == (int)mpg123_errors.MPG123_OK)
{
copiedIndex = true;
}
}
}
return copiedIndex;
}
_sourceHandle and _destinationHandle may not be IntPtr.Zero, that was my mistake. Thanks for Stargateur, really nice help!

Related

Passing an array of pointers to an unmanaged DLL function

I am trying to create and pass an array of pointers to an unmanaged DLL function using the following C# code.
[DllImport("libantumbra.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint AnCtx_Init(IntPtr ctx);
//create context
this.ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
AnCtx_Init(ptr);//returns 0 (non-error)
this.ctx = (IntPtr)Marshal.PtrToStructure(ptr, typeof(IntPtr));
[DllImport("libantumbra.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AnDevice_GetList(IntPtr ctx, out IntPtr outdevs, out int outndevs);
IntPtr devs, ndevs;
AnDevice_GetList(ctx, out devs, out ndevs); //exception occurs here
However upon my last call I receive an AccessViolationException. I think it has to do with the array pointer I am passing however I have not been able to find a solution.
The end goal I am trying to achieve here is to pass a pointer to AnDevice_GetList and with the parameter outdevs be left with an array that has been populated by the DLL.
Let me know if you need any further info or have any ideas for me to try.
Edit:
Here is the function I am trying to call.
Header file:
An_DLL AnError AnDevice_GetList(AnCtx *ctx, AnDeviceInfo ***outdevs,
size_t *outndevs);
typedef struct AnDevice AnDevice;
typedef int AnError;
typedef struct AnCtx AnCtx;
And implementation:
AnError AnDevice_GetList(AnCtx *ctx, AnDeviceInfo ***outdevs, size_t *outndevs)
{
An_LOG(ctx, AnLog_DEBUG, "enumerate devices...");
libusb_device **udevs;
ssize_t ndevs = libusb_get_device_list(ctx->uctx, &udevs);
if (ndevs < 0) {
An_LOG(ctx, AnLog_ERROR, "libusb_get_device_list: %s",
libusb_strerror(ndevs));
return AnError_LIBUSB;
}
AnDeviceInfo **devs = malloc((ndevs + 1) * sizeof *devs);
if (!devs) {
An_LOG(ctx, AnLog_ERROR, "malloc: %s", strerror(errno));
return AnError_MALLOCFAILED;
}
memset(devs, 0, (ndevs + 1) * sizeof *devs);
size_t j = 0;
for (ssize_t i = 0; i < ndevs; ++i) {
libusb_device *udev = udevs[i];
AnDeviceInfo info;
An_LOG(ctx, AnLog_DEBUG, "device: bus %03d addr %03d",
libusb_get_bus_number(udev), libusb_get_device_address(udev));
if (populate_info(ctx, &info, udev))
continue;
An_LOG(ctx, AnLog_DEBUG, "vid 0x%04x pid 0x%04x",
info.devdes.idVendor, info.devdes.idProduct);
if (!match_vid_pid(info.devdes.idVendor, info.devdes.idProduct)) {
An_LOG(ctx, AnLog_DEBUG, " does not match Antumbra VID/PID");
continue;
}
devs[j] = malloc(sizeof *devs[j]);
if (!devs[j]) {
An_LOG(ctx, AnLog_ERROR, "malloc: %s", strerror(errno));
continue;
}
libusb_ref_device(udev);
*devs[j] = info;
++j;
}
libusb_free_device_list(udevs, 1);
*outdevs = devs;
*outndevs = j;
return AnError_SUCCESS;
}
Your unmanaged function is declared like this:
AnError AnDevice_GetList(AnCtx *ctx, AnDeviceInfo ***outdevs, size_t *outndevs)
You should translate that as:
[DllImport("libantumbra.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AnDevice_GetList(IntPtr ctx, out IntPtr outdevs,
out IntPtr outndevs);
And this is almost exactly as you have done. The only differences are that the return value is int and the outndevs parameter is of type IntPtr. That's because size_t is pointer sized on the platforms that I am aware of.
Call it like this:
IntPtr ctx = ...; // create a context somehow
IntPtr devs;
IntPtr ndevs;
int retval = AnDevice_GetList(ctx, out devs, out ndevs);
if (retval != AnError_SUCCESS)
// handle error
So, where could your code be going wrong? One likely explanation is that the context that you pass is invalid. Another possibility is that you execute 64 bit code and the incorrect size of outndevs in your translation caused the error.
This is a pretty hard API to call using p/invoke. What can you do now with devs. You can copy the values into an IntPtr[] array easily enough. And presumably the library has functions that operate on these opaque device pointers. But you have to keep hold of devs and pass it back to the library to deallocate it. Presumably the library exports a function to do that?
Based on your comments and various updates, it looks like you are not getting a proper context. We can only guess, but I expect that AnCtx_Init is declared as
AnError AnCtx_Init(AnCtx **octx)
That is a pointer to opaque context AnCtx*. Translate that as:
[DllImport("libantumbra.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AnCtx_Init(out IntPtr octx);
Call it like this:
IntPtr ctx;
int retval = AnCtx_Init(out ctx);
if (retval != AnError_SUCCESS)
// handle error
The big thing that you have to do now is start checking for errors. Unmanaged code won't throw exceptions. You need to do error checking yourself. It is laborious, but it must be done. Take it one function at a time. Once you are sure a function call is working, move on to the next.
Some things don't make sense in your example. You create ptr2 and allocate space for it but never copy anything into that space, and you don't pass it to your AnDevice_GetList function so that seems completely unnecessary. You create ptArray but never use it anywhere either.
In this code, you're creating a managed array of IntPtr structures, and allocating memory for each of them to point to, and the size of what they are pointing to is the size of a single pointer:
IntPtr[] ptArray = new IntPtr[] {
Marshal.AllocHGlobal(IntPtr.Size),
Marshal.AllocHGlobal(IntPtr.Size)
};
To really help we need a clear understanding of exactly what AnDevice_GetList is going to do. If AnDevice_GetList is populating an array of pointers, what do they point to? Do they point to structures that were allocated by AnDevice_GetList? If so, then what you want to do is to create an array of IntPtr and pin it while you make the unmanaged call. Since you're creating an array for the call to fill, do NOT pass the array as an out parameter.
[DllImport("libsomething.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint AnDevice_GetList(IntPtr outdevs);
IntPtr[] ptArray = new IntPtr[numberOfPointersRequired];
GCHandle handle = GCHandle.Alloc(ptArray);
try
{
AnDevice_GetList(handle.AddrOfPinnedObject());
}
finally
{
handle.Free();
}
I left off the other parameters, because I have no idea what you're doing with them or how you're expecting them to be handled.

importing a C dll and method into c#

I've been having problems getting a C method to work in C# - the thing compiles and runs fine in C, returning the proper result for the device ID - but with windows the function appears to not be building the string properly. The code for the source that works in C follows, from the interception.dll examples on oblita.com:
int main()
{
using namespace std;
InterceptionContext context;
InterceptionDevice device;
InterceptionStroke stroke;
wchar_t hardware_id[500];
raise_process_priority();
context = interception_create_context();
interception_set_filter(context, interception_is_keyboard, INTERCEPTION_FILTER_KEY_DOWN | INTERCEPTION_FILTER_KEY_UP);
interception_set_filter(context, interception_is_mouse, INTERCEPTION_FILTER_MOUSE_LEFT_BUTTON_DOWN);
while(interception_receive(context, device = interception_wait(context), &stroke, 1) > 0)
{
if(interception_is_keyboard(device))
{
InterceptionKeyStroke &keystroke = *(InterceptionKeyStroke *) &stroke;
if(keystroke.code == SCANCODE_ESC) break;
}
size_t length = interception_get_hardware_id(context, device, hardware_id, sizeof(hardware_id));
if(length > 0 && length < sizeof(hardware_id))
wcout << hardware_id << endl;
interception_send(context, device, &stroke, 1);
}
interception_destroy_context(context);
return 0;
Now, i've imported the DLL in C# as such, which should cover all of the variable conversions correctly:
[DllImport("interception.dll", EntryPoint = "interception_get_hardware_id", CallingConvention = CallingConvention.Cdecl)]
public static extern int GetHardwareID(IntPtr context, int device, ref StringBuilder idbuffer, uint buffer_size);
here is the code i'm trying to fire to get the device ID in C#:
{
IntPtr context;
int device;
Interception.Stroke stroke = new Interception.Stroke();
context = Interception.CreateContext();
Interception.SetFilter(context, Interception.IsKeyboard, Interception.Filter.All);
StringBuilder hardwareID = new StringBuilder();
while (Interception.Receive(context, device = Interception.Wait(context), ref stroke, 1) > 0)
{
int hardwareID_length = Interception.GetHardwareID(context, device, ref hardwareID, Convert.ToUInt32(hardwareID.Length));
if (hardwareID_length > 0 && hardwareID_length < Convert.ToUInt32(hardwareID.Length))
Console.WriteLine("ID result: ", hardwareID);
Console.WriteLine("SCAN CODE: {0}/{1}", stroke.key.code, stroke.key.state);
if (stroke.key.code == ScanCode.X)
{
stroke.key.code = ScanCode.Y;
}
Interception.Send(context, device, ref stroke, 1);
// Hitting escape terminates the program
if (stroke.key.code == ScanCode.Escape)
{
break;
}
}
Interception.DestroyContext(context);
}
}
The block inside the if statement never fires - it's not printing the ID properly, which i believe means the stringbuilder isn't getting populated properly like the wchar_t would be in C. The value is 0, which means it's never fed the right information by the pointer, right? What can i do to fix this? Any help is much appreciated.
It should be noted that the scancode works right - it detects keystrokes and even replaces the x with y as expected.
As a result of my own digging and lots of trial and error, here's how to get this to work:
{
[DllImport("interception.dll", EntryPoint = "interception_get_hardware_id", CallingConvention = CallingConvention.Cdecl)]
public static unsafe extern int GetHardwareID(IntPtr context, int device, out void* idbuffer, uint buffer_size);
//Note the call is unsafe - because we're using the void* pointer.
{(inside an unsafe block of code)
void* hardwareID;
//call function as follows:
int result = Interception.GetHardwareID(context, device, out hardwareID, 5000);
//i use 5000 because it works. i'm sure there's better ways to do it but i don't want to spend another few months on figuring it out.
IntPtr hardwareConverted = new IntPtr(hardwareID);
//this marshals the void* into an IntPtr that you can play around with as normal, in managed memory.

How do I read a uint from a pointer with Marshalling?

I have a native method which needs a pointer to write out a dword (uint).
Now I need to get the actual uint value from the (Int)pointer, but the Marshal class only has handy methods for reading (signed) integers.
How do I get the uint value from the pointer?
I've searched the questions (and Google), but couldn't really find what I needed.
Sample (not working) code:
IntPtr pdwSetting = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)));
try
{
// I'm trying to read the screen contrast here
NativeMethods.JidaVgaGetContrast(_handleJida, pdwSetting);
// this is not what I want, but close
var contrast = Marshal.ReadInt32(pdwSetting);
}
finally
{
Marshal.FreeHGlobal(pdwSetting);
}
The return value from the native function is a dword between 0 and 255 with 255 being full contrast.
Depending on whether you may use usafe code you can even do:
static unsafe void Method()
{
IntPtr pdwSetting = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)));
try
{
NativeMethods.JidaVgaGetContrast(_handleJida, pdwSetting);
var contrast = *(uint*)pdwSetting;
}
finally
{
Marshal.FreeHGlobal(pdwSetting);
}
}
Note, that a C++ function pointer like
void (*GetContrastPointer)(HANDLE handle, unsigned int* setting);
can be marshaled as
[DllImport("*.dll")]
void GetContrast(IntPtr handle, IntPtr setting); // most probably what you did
but also as
[DllImport("*.dll")]
void GetContrast(IntPtr handle, ref uint setting);
which lets you write code like
uint contrast = 0; // or some other invalid value
NativeMethods.JidaVgaGetContrast(_handleJida, ref contrast);
which is superior in both performance and readability.
You can simply cast it to uint:
uint contrast = (uint)Marshal.ReadInt32(pdwSetting);
For example:
int i = -1;
uint j = (uint)i;
Console.WriteLine(j);
outputs 4294967295.
Use the Marshal.PtrToStructure overload that takes an IntPtr and a type and pass in typeof(uint) - that ought to work!
Hope this helps!

P/Invoke C# struct with strings to C void*

I'm having a problem creating a C# P/invoke wrapper around a third party C library. In particular, the library has a method with the signature
int command(SomeHandle *handle, int commandNum, void *data, int datasize);
It is a wildcard method that does different things depending on commandNum. data can be a pointer to anything, like a single integer, or a char[], or a struct of some kind (my problem).
I have declared the wrapper as follows:
[DllImport("LIBRARY.DLL", EntryPoint = "command")]
public static extern int Command(IntPtr Handle, int CommandNum, [In, Out] IntPtr Data, int DataSize);
Now, when i call it with an opcode to fill a byte[] it works:
//WORKS, Buffer contains "library 1.0" after the call
const int BUFFER_SIZE = 128;
byte[] Buffer = new byte[BUFFER_SIZE];
int BytesWritten = 0;
GCHandle BufferHandle = GCHandle.Alloc(Buffer, GCHandleType.Pinned);
try
{
BytesWritten = Command(MyHandle, GET_VERSION, BufferHandle.AddrOfPinnedObject(), BUFFER_SIZE);
}
finally
{
BufferHandle.Free();
}
However, when I try the same with a simple struct, I cannot make it work, no matter what I try. the struct looks like this:
public struct FormatInfoType
{
public int Format;
public IntPtr Name; //const char*
public IntPtr Extension; //const char*
}
Here I am supposed to fill "Format" with an int (say, 1) and then the call to "command(...)" is meant to give me back the name and extension fields
If I pass this struct, the code compiles and runs correctly, but the values in the struct are never modified. If I change the IntPtr's to Strings or StringBuilders (and I've tried a myriad of MarshalAs attributes), then I cannot get the IntPtr to the struct because the it becomes non-blittable and the GCHandle line throws an exception.
Any help on this would be greatly appreciated.
EDIT:
I've tried many ways to call command() with the structure, but currently it looks like this:
FormatInfoType f = new FormatInfoType();
f.Format = 1;
f.Name = IntPtr.Zero;
f.Extension = IntPtr.Zero;
GCHandle fHandle = GCHandle.Alloc(f, GCHandleType.Pinned);
try
{
Command(MyHandle, GET_FORMAT_INFO, fHandle.AddrOfPinnedObject(), Marshal.SizeOf(f));
}
finally
{
fHandle.Free();
}
You can overload p/invoke signatures, try:
[DllImport("LIBRARY.DLL", EntryPoint = "command")]
public static extern int Command(IntPtr Handle, int CommandNum, ref FormatInfoType Data, int DataSize);

C#: Search a byte[] array in another process's memory

How is it possible to search for a byte[] array in the memory of another process and then get the address at the place where the byte[] array is located?
I want to write a byte array into the memory of another process(WriteProcessMemory()).One of the parameters of that call is uint Address.Well I want to get the address by searching a byte array into the process.
For example I search for {0xEB ,0x20,0x68,0x21,0x27,0x65, ??, 0x21,0x64,0xA1}
We assume that this array is placed only at one place in the memory of the process I'd like to write memory to.
To get that address,I have to search for that byte array.
Is it possible to be done in C#?
EDIT: This is for native applications,NOT .NET. No need to downvote my question,there are components for C++ that do this,I just want to do it in C#.
Thanks for understanding!
Is it possible to be done in C#?
Everithing is possible in c#(or any other languge), u just need to fiind how;
Hard coding here:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[Out] byte[] lpBuffer,
int dwSize,
out int lpNumberOfBytesRead
);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CloseHandle(IntPtr hObject);
static void Main(string[] args)
{
Process[] procs = Process.GetProcessesByName("explorer");
if (procs.Length <= 0) //proces not found
return; //can replace with exit nag(message)+exit;
IntPtr p = OpenProcess(0x10 | 0x20, true, procs[0].Id); //0x10-read 0x20-write
uint PTR = 0x0; //begin of memory
byte[] bit2search1 = {0xEB ,0x20,0x68,0x21,0x27,0x65}; //your bit array until ??
int k = 1; //numer of missing array (??)
byte[] bit2search2 = {0x21,0x64,0xA1};//your bit array after ??
byte[] buff = new byte[bit2search1.Length+1+bit2search2.Length]; //your array lenght;
int bytesReaded;
bool finded = false;
while (PTR != 0xFF000000) //end of memory // u can specify to read less if u know he does not fill it all
{
ReadProcessMemory(p, (IntPtr)PTR, buff, buff.Length, out bytesReaded);
if (SpecialByteCompare(buff, bit2search1,bit2search2,k))
{
//do your stuff
finded = true;
break;
}
PTR += 0x1;
}
if (!finded)
Console.WriteLine("sry no byte array found");
}
private static bool SpecialByteCompare(byte[] b1, byte[] b2, byte[] b3, int k) //readed memory, first byte array, second byte array, number of missing byte's
{
if (b1.Length != (b2.Length + k + b3.Length))
return false;
for (int i = 0; i < b2.Length; i++)
{
if (b1[i] != b2[i])
return false;
}
for (int i = 0; i < b3.Length; i++)
{
if (b1[b2.Length + k + i] != b3[i])
return false;
}
return true;
}
}
}
I guess you could use the ReadProcessMemory Windows API call. There's even a premade P/Invoke signature for it so you don't need to bother with manually crafting it. You page through the memory of the process, search through it for your pattern and you're done.
You'll want to use these APIs:
[DllImport("Kernel32.Dll")]
public static extern uint VirtualQueryEx(IntPtr ProcessHandle, uint Address, ref MEMORY_BASIC_INFORMATION MemInfo, int MemInfoLength);
[DllImport("Kernel32.Dll")]
public static extern bool ReadProcessMemory(IntPtr ProcessHandle, uint Address, byte[] Buffer, uint Size, ref uint BytesRead);
[DllImport("Kernel32.Dll")]
public static extern bool WriteProcessMemory(IntPtr ProcessHandle, uint Address, byte[] Buffer, uint Size, ref uint BytesRead);
pinvoke.net is a great resource for Windows API calls. I wrote a trainer for GTA: Vice City that uses these calls if you want to check out the code on sourceforge. The code isn't pretty, it was a long time ago and I just threw it together, but there are helper classes for enumerating memory regions for a process and searching for certain bytes or strings.
This may help you find the right way:
private static int GetMemoryAddressOfString(byte[] searchedBytes, Process p)
{
//List<int> addrList = new List<int>();
int addr = 0;
int speed = 1024*64;
for (int j = 0x400000; j < 0x7FFFFFFF; j+= speed)
{
ManagedWinapi.ProcessMemoryChunk mem = new ProcessMemoryChunk(p, (IntPtr)j, speed + searchedBytes.Length);
byte[] bigMem = mem.Read();
for (int k = 0; k < bigMem.Length - searchedBytes.Length; k++)
{
bool found = true;
for (int l = 0; l < searchedBytes.Length; l++)
{
if(bigMem[k+l] != searchedBytes[l])
{
found = false;
break;
}
}
if(found)
{
addr = k+j;
break;
}
}
if (addr != 0)
{
//addrList.Add(addr);
//addr = 0;
break;
}
}
//return addrList;
return addr;
}
Is it possible to be done in C#?
Yes. But very hard. It is hard from a native application where there is no impedance mismatched with the unmanaged view of processes and their memory maps you will need to use.
Considerations:
You will need permission to open the process to get a handle.
While the virtual memory space of a 32bit process is from two to four GB in size (depending on host OS and /3GB switch), much of this address range will not be allocated, and reading it will cause a page fault. You really need to find out what pages are allocated and for what to avoid lots of invalid page accesses.
Suggestions:
Do you really really need to do this? Seriously this will be hard.
Consider doing a native application, this will avoid working across the native/managed fence (this could include a native library with a managed driver application).
Do you really need to do this?
Consider doing the work inside the target process. This will require some cleverness (documented) to inject a thread, but should then be much faster.
Start by reading up on Windows how process memory works (start with Windows Internals and (can't recall its name in the latest edition) Jeffrey Richter's book on Win32 application development.
Do you really need to do this? There must be something simpler... could you automated a debugger?

Categories