在我的C#应用程序中,我有一个IntPtr类型的变量lpData(从对非托管代码的调用中获得),它指向一个字符串。
我必须用另一个值替换此字符串。
我试过了:
int RegQueryValueExW_Hooked(
IntPtr hKey,
string lpValueName,
int lpReserved,
ref Microsoft.Win32.RegistryValueKind lpType,
IntPtr lpData,
ref int lpcbData)
{
lpData = Marshal.StringToHGlobalUni("new string");
...
}
但这似乎并没有取代实际的字符串。
有人能指出我如何做到这一点的正确方向吗?
由于
答案 0 :(得分:2)
当然它不会替换字符串 - 您将获得指向调用者具有值的字符串的指针。您只是替换“局部变量”(参数)的值,这不会改变调用方的任何内容。
如果您要修改原来的指针值(并确保你其实想的是,这是在“奇怪的错误”潜伏 - 它很容易覆盖周边变量,忘掉空终止等) ,您可以使用Marshal.Copy
,例如:
var bytes = Encoding.Unicode.GetBytes("your string\0");
Marshal.Copy(bytes, 0, lpData, bytes.Length);
再次 - 这是一种非常危险的行为,你不应该这样做。你违反了参数传递等隐含的几个合同。
现在,我已经回答了你的问题的,让我谈谈你对真正需要多么错误做到这一点(和这个有很大关系到你的其他职位有关使用StringBuilder)。
您正在尝试修改作为参数传递给您的值。但是,字符串是由调用者分配的。你甚至不知道它有多久!如果您开始将数据复制到该指针,您将覆盖例如数据。完全不同的变量,只是随机发生在字符串之后。这被认为是“非常糟糕”。
相反,您想要做的是遵循RegQueryValueEx具有的正确过程(http://msdn.microsoft.com/en-us/library/windows/desktop/ms724911(v=vs.85).aspx)。这意味着您首先必须检查lpcbData值。如果它足够大以容纳您想要写入的所有字节,则只需将数据写入lpData并将lpcbData值设置为适当的长度。如果没有,您仍然设置lpcbData,但返回ERROR_MORE_DATA。然后调用者应该再次使用更大的缓冲区调用RegQueryValueEx。
示例代码如下:
string yourString = "Your string";
int RegQueryValueExW_Hooked(
IntPtr hKey,
string lpValueName,
int lpReserved,
ref Microsoft.Win32.RegistryValueKind lpType,
IntPtr lpData,
ref int lpcbData)
{
var byteCount = Encoding.Unicode.GetByteCount(yourString);
if (byteCount > lpcbData)
{
lpcbData = byteCount;
return ERROR_MORE_DATA;
}
if (lpData == IntPtr.Zero)
{
return ERROR_SUCCESS;
}
lpcbData = byteCount;
var bytes = Encoding.Unicode.GetBytes(yourString);
Marshal.Copy(bytes, 0, lpData, bytes.Length);
return ERROR_SUCCESS;
}
请注意,这正是我在快速浏览文档后所写的内容 - 您应该进一步调查,并确保您正在处理所有可能的情况。在这种情况下,.NET不能保护您,可以导致重大问题!