简体   繁体   English

C#-无法将IntPtr编组为正确的字符串

[英]C# - Cannot Marshal IntPtr To String Correctly

This line of code has been baffling me! 这行代码让我感到困惑!

string s = Marshal.PtrToStringAnsi((IntPtr)((Int32)Buffer + 
            Marshal.SizeOf(typeof(Struct))));

Here is the rest of the function. 这是其余的功能。

            Api.LvItem lvItem = new Api.LvItem();
            IntPtr lpLocalBuffer = Marshal.AllocHGlobal(1024);
            uint pid;
            uint thread = Api.GetWindowThreadProcessId(hWnd, out pid);
            IntPtr hProcess = Api.OpenProcess(0x001f0fff, false, (int)pid);
            IntPtr lpRemoteBuffer = Api.VirtualAllocEx(hProcess, IntPtr.Zero, 1024, 0x1000, 4);
            lvItem.mask = 1;
            lvItem.iItem = index;
            lvItem.iSubItem = subitem;
            lvItem.pszText = (IntPtr)((int)lpRemoteBuffer + Marshal.SizeOf(typeof(Api.LvItem)));
            lvItem.cchTextMax = 50;
            Api.WriteProcessMemory(hProcess, lpRemoteBuffer, ref lvItem, Marshal.SizeOf(typeof(Api.LvItem)), 0);
            Api.SendMessage(hWnd, 0x1005, IntPtr.Zero, lpRemoteBuffer);
            Api.ReadProcessMemory(hProcess, lpRemoteBuffer, lpLocalBuffer, 1024, 0);
            string ret = Marshal.PtrToStringAnsi((IntPtr)((int)lpLocalBuffer + Marshal.SizeOf(typeof(Api.LvItem))));
            Marshal.FreeHGlobal((IntPtr)lpLocalBuffer);
            Api.VirtualFreeEx(hProcess, lpRemoteBuffer, 0, 0x8000);
            Api.CloseHandle(hProcess);
            return ret;

This code is used to get the text of each of the items in a listview of another process. 此代码用于获取另一个进程的列表视图中每个项目的文本。 I followed code (semi) from here : http://taylorza.blogspot.com/2009/08/archive-hacking-my-way-across-process.html 我从这里遵循代码(半): http : //taylorza.blogspot.com/2009/08/archive-hacking-my-way-across-process.html

I'm sorry about the use of 0x1005. 对0x1005的使用感到抱歉。 That's the code for the LV_GETITEM message. 这是LV_GETITEM消息的代码。

I've narrowed it down to being related to the platform. 我将其范围缩小到与平台相关。 It works on x64 and AnyCPU, while it does not work on x86. 它适用于x64和AnyCPU,而不适用于x86。 how would I go about changing the size differences in memory allocation, etc 我将如何更改内存分配等中的大小差异

It returns the value correctly when used in a console application. 在控制台应用程序中使用时,它会正确返回该值。 But when I use this code (and the rest of it) in a .DLL which is invoked via reflection, the code returns a string which is not correct. 但是,当我在通过反射调用的.DLL中使用此代码(及其其余部分)时,该代码返回的字符串不正确。 It appears empty, but is not in fact null. 它显示为空,但实际上不为空。 Perhaps just white space... 也许只是空白...

Has anybody had a similar experience with this trouble marshaling? 有没有人遇到过类似的麻烦编组经验? It's been puzzling me for a good three hours now... 现在已经困扰了我三个小时了...

ANY help or ANY ideas or ANYTHING is greatly appreciated! 任何帮助或任何想法或任何东西都将不胜感激!

It appears that you are trying to read the memory of another process. 看来您正在尝试读取另一个进程的内存。 You are sending an LV_GETITEM message to a list view control. 您正在将LV_GETITEM消息发送到列表视图控件。 This requires you to allocate memory in the virtual address space of that other process. 这要求您在该其他进程的虚拟地址空间中分配内存。 Which you did with the call to VirtualAllocEx . 您对VirtualAllocEx的调用做了什么。

So far so good, but here's the kicker. 到目前为止,一切都很好,但这是关键。 You need the struct that you allocate to be the right layout for the target process. 您需要分配的结构才能成为目标进程的正确布局。 Now, let's assume that the target process is a 64 bit process. 现在,让我们假设目标进程是一个64位进程。 In which case the struct contains 64 bit pointers. 在这种情况下,该结构包含64位指针。 When your process is also 64 bit then the struct that you defined will have 64 bit pointers. 当您的进程也是64位时,则您定义的结构将具有64位指针。 But when your process is 32 bit, any pointers in the struct will be 32 bit. 但是,当您的进程是32位时,该结构中的任何指针都将是32位。

So, now we have a situation where the struct in your process has a different layout from the struct in the target process. 因此,现在我们遇到一种情况,您的流程中的结构与目标流程中的结构具有不同的布局。 That mismatch is enough to make all of this effort fail. 这种不匹配足以使所有这些努力失败。 In order to have any chance of making this work, you would need to declare your struct so that its layout matched the 64 bit layout. 为了有机会进行这项工作,您需要声明结构,以使其布局与64位布局匹配。 Given that you are only accessing a handful of fields, it may just be simpler to allocate a block of memory the right size (perhaps a byte array) and read/write the fields manually. 假设您只访问少数几个字段,那么分配一个适当大小的内存块(也许是字节数组)并手动读取/写入字段可能会更简单。 And avoid struct marshalling. 并避免结构编组。

Even then I am doubtful that a 32 bit process is even able to poke at a 64 bit process that way. 即使那样,我仍然怀疑32位进程是否能够以这种方式戳入64位进程。 You can do it in the other direction, from a 64 bit process to a 32 bit process. 您可以从64位处理到32位处理的另一方向进行操作。 But I have tried and never succeeded in the direction that you are attempting. 但是我已经尝试过并且从未成功地朝着您尝试的方向发展。

All the indications are that you should stick to a 64 bit processes for this task. 所有迹象表明,您应该坚持执行此任务的64位进程。 Or alternatively find an officially supported way to do whatever it is you are doing. 或者,找到一种官方支持的方式来做您正在做的事情。 For example, if you just want to read the contents of an explorer view, there's a shell API for that. 例如,如果您只想阅读资源管理器视图的内容,则有一个Shell API。


As an aside, please stop using magic constants instead of message identifier names. 另外,请停止使用魔术常数而不是消息标识符名称。 Nobody likes to try and understand what 0x1005 means. 没有人喜欢尝试理解0x1005含义。 Declare a constant named LV_GETITEM . 声明一个名为LV_GETITEM的常量。 You also appear to perform no error checking at all. 您似乎也根本不执行任何错误检查。 That's also going to make life hard for you. 这也将使您的生活艰难。 If one of the API calls fails, how will you ever find out about that? 如果其中一个API调用失败,您将如何找到呢?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM