我试图在C#中处理WM_MOUSEMOVE消息.
从lParam获取X和Y坐标的正确方法是什么?这是一种IntPtr?
这是我的代码:
using (Process game = Process.Start(new ProcessStartInfo() {
FileName="DatabaseCheck.exe",
RedirectStandardOutput = true,
CreateNoWindow = true,
UseShellExecute = false }))
{
lblLoad.Text = "Loading";
int Switch = 0;
while (game.MainWindowHandle == IntPtr.Zero)
{
Switch++;
if (Switch % 1000 == 0)
{
lblLoad.Text += ".";
if (lblLoad.Text.Contains("...."))
lblLoad.Text = "Loading.";
lblLoad.Update();
game.Refresh();
}
}
Run Code Online (Sandbox Code Playgroud)
问题是,那个游戏.MainWindowHandle总是IntPtr.Zero.我需要找到运行过程的IntPtr以确认游戏是由启动器启动的,所以我让游戏发送它的IntPtr并让启动器响应它是否正常.但为此,我必须具体了解运行过程的IntPtr.
提前致谢!
我想我理解IntPtr的使用,虽然我真的不确定.
我从MSDN复制IDisposable模式只是为了看看我能从中得到什么,虽然我在大多数情况下理解它,但我不知道如何正确实现IntPtr,或者甚至不知道它应该"指向什么" "参考或参考.最重要的是,我不知道如何为IntPtr分配或转换整数,字符串,字符,双精度等来创建指针.
此外,IntPtr是否需要使用不安全的代码?
无论如何,这里有一些代码只是为了描绘我正在谈论的内容:
namespace Utilities
{
class Disposer : IDisposable
{
private IntPtr handle;
private Component component = new Component();
private bool disposed = false;
public Disposer(IntPtr handle)
{
this.handle = handle;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if(!this.disposed)
{
if (disposing)
{
component.Dispose();
}
CloseHandle(handle);
handle = IntPtr.Zero;
disposed = true;
}
}
[System.Runtime.InteropServices.DllImport("Kernal32")]
private extern static Boolean CloseHandle(IntPtr handle);
}
public unsafe class ExecuteMain
{
Object …Run Code Online (Sandbox Code Playgroud) 我有一些像这样的结构
struct MyStruct
{
public int field1;
public int field2;
public int field3;
}
Run Code Online (Sandbox Code Playgroud)
我有指向此结构数组的指针.所以,我需要从这个指针获取数组.我试图使用Marshal.PtrToStructure,但我有内存读取错误.这是我的方法:
public MyStruct[] GetArrayOfStruct(IntPtr pointerToStruct, int length)
{
var sizeInBytes = Marshal.SizeOf(typeof(TCnt));
MyStruct[] output = new MyStruct[length];
for (int i = 0; i < length; i++)
{
IntPtr p = new IntPtr((pointerToStruct.ToInt32() + i * sizeInBytes));
output[i] = (MyStruct)System.Runtime.InteropServices.Marshal.PtrToStructure(p, typeof(MyStruct));
}
return output;
}
Run Code Online (Sandbox Code Playgroud)
那么,我做错了什么?
RegOpenKeyEx当我在页面上注意到这条评论时,我正在查看P/Invoke声明:
更改
IntPtr为UIntPtr:使用IntPtr句柄调用时,您将遇到溢出.UIntPtr如果您希望在32位和64位平台上正常工作,则是正确的选择.
这并没有太大的意义对我说:都IntPtr和UIntPtr应该代表指针因此其大小应与OS的位数-无论是32位或64位.由于这些不是数字而是指针,因此它们的带符号数值应该无关紧要,只有表示它们指向的地址的位.我想不出为什么这两者之间会有什么不同,但是这个评论让我不确定.
是否有使用的具体原因UIntPtr而不是IntPtr?根据文件:
该
IntPtr类型是符合CLS,而UIntPtr类型不是.IntPtr在公共语言运行库中仅使用该类型.UIntPtr提供的类型主要是为了保持与IntPtr类型的架构对称性.
当然,这意味着没有区别(只要有人不尝试将值转换为整数).所以pinvoke.net的上述评论是错误的吗?
编辑:
在阅读了MarkH的回答之后,我做了一些检查,发现.NET应用程序不是大地址识别,并且在32位模式下编译时只能处理2GB的虚拟地址空间.(可以使用hack打开大地址识别标志,但MarkH的答案显示.NET Framework内的检查会破坏因为地址空间仅为2GB,而不是3GB.)
这意味着指针可以拥有的所有正确的虚拟内存地址(就.NET Framework而言)将介于0x00000000和0x7FFFFFFF之间.当此范围转换为有符号时int,没有值为负值,因为未设置最高位.这强化了我的信念,即使用IntPtr与UIntPtr没有区别.我的推理是否正确?
Fermat2357指出上面的编辑是错误的.
请注意,我不太确定这个问题属于这个网站,但我尝试建设性的.
为什么代码
IntPtr ptr = new IntPtr(1234);
Console.WriteLine(string.Format("{0:X8}", ptr));
Console.WriteLine(ptr.ToString("X8"));
Console.WriteLine(string.Format("{0:X8}", ptr.ToInt32()));
Run Code Online (Sandbox Code Playgroud)
产量
1234
000004D2
000004D2
Run Code Online (Sandbox Code Playgroud)
为什么IntPtr在格式化时请求将十六进制格式直接应用于参数?有没有任何已知的论据反对设计功能 - ?
如果没有针对此类设计的论据,那么我应该通过哪个渠道向Microsoft报告此问题?
另请注意,IntPtr如果请求,调试器将以十六进制显示值.
我发现打印输出IntPtr值非常直观且相对频繁.我也找到了使用第一行的其他人编写的代码,显然期望十六进制结果,但实际上结果是不同的.我也花了一些时间来注意这个问题,这使得理解日志消息更加复杂.
可能是一个菜鸟问题,但互操作不是我的优点之一.
除了限制重载次数之外,有任何理由我应该声明我的DllImports:
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
Run Code Online (Sandbox Code Playgroud)
并像这样使用它们:
IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(formatrange));
Marshal.StructureToPtr(formatrange, lParam, false);
int returnValue = User32.SendMessage(_RichTextBox.Handle, ApiConstants.EM_FORMATRANGE, wParam, lParam);
Marshal.FreeCoTaskMem(lParam);
Run Code Online (Sandbox Code Playgroud)
而不是创建目标重载:
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref FORMATRANGE lParam);
Run Code Online (Sandbox Code Playgroud)
使用它像:
FORMATRANGE lParam = new FORMATRANGE();
int returnValue = User32.SendMessage(_RichTextBox.Handle, ApiConstants.EM_FORMATRANGE, wParam, ref lParam);
Run Code Online (Sandbox Code Playgroud)
by ref重载最终更容易使用,但我想知道是否存在我不知道的缺点.
编辑:
到目前为止,有很多很棒的信息.
@P爸爸:你有一个基于抽象(或任何)类的结构类的例子吗?我将签名改为:
[DllImport("user32.dll", SetLastError = true)]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, [In, …Run Code Online (Sandbox Code Playgroud) 我陷入了一项看似微不足道的任务,需要你的帮助.
我需要编写一个带有以下签名的方法:
System.Array ToIntPtrArray(System.Array a)
Run Code Online (Sandbox Code Playgroud)
其中一个实际的参数可以是任意的阵列指针类型(例如int*[],long**[],void*[,]),并用类型的元素返回相同形状的阵列System.IntPtr具有相同的数值作为输入数组的元素.问题是如果我事先不知道它们的类型,我不明白如何提取指针的数值.
例如,如果我事先知道我的参数总是类型void*[],我可以编写如下方法:
unsafe IntPtr[] ToIntPtrArray(void*[] a)
{
var result = new IntPtr[a.Length];
for (int i = 0; i < a.Length; i++)
result[i] = (IntPtr) a[i];
return result;
}
Run Code Online (Sandbox Code Playgroud)
但问题是它可能不是void*[],但是void**[]或其他任何东西,该方法应该能够处理所有情况.
我想知道获得进程窗口位置的方式.我一直在网上寻找,但没有结果.谢谢 :)
Process[] processes = Process.GetProcessesByName("notepad");
Process lol = processes[0];
IntPtr p = lol.MainWindowHandle;
Run Code Online (Sandbox Code Playgroud) 我的C#类中有一个IntPtr字段.
它包含对C++库中对象的引用.
protected IntPtr ThingPtr;
Run Code Online (Sandbox Code Playgroud)
在某些阶段,我可能会或可能不会初始化它.
ThingPtr = FunctionInMyCplusplusLibrary();
Run Code Online (Sandbox Code Playgroud)
我想知道在这种情况下检查是否为null是有意义的(检查它是否已被初始化)
if(ThingPtr == null)
{
//Do stuff
}
Run Code Online (Sandbox Code Playgroud)