我正在尝试完成与这里所做的大致相同的事情http://www.vbforums.com/showthread.php?t=449171
但是使用 C#,而不是 VB。最让我困惑的是代码的 C++ 部分。我对 C++ 几乎没有经验,而且我一次又一次地尝试让这个“.dll”被谈论,但如果不改变一些东西,它就无法正确编译(我必须将 GetModuleHandle 部分更改为具有 Text( “”)在其中,等等)
然后,当我在 C# 中安装它时,出现错误“无法为 GetAddr() 找到合适的入口点,即使我遵循所解释的相同 P/Invoke 签名(使用 C# 语法而不是 VB)” 。
有人可以帮助我吗?我无法正确制作此 C++ .dll。我什至不知道制定正确类型的项目来执行此操作的适当方法。下面列出了有问题的 C++ 代码,我使用的是 Visual Studio 2010。
#include "stdafx.h"
#pragma data_seg(".shared")
char sharedStr[255] = "a";
char sharedRichTextBoxString[255] = "a";
int addr = 0;
HMODULE module = 0;
int flag = 0;
#pragma data_seg()
#pragma comment(linker, "/SECTION:.shared,RWS")
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if(flag == 0)
{
module = GetModuleHandle("C:\\Program Files\\Microsoft Visual Studio\\MyProjects\\EditStreamCallBack\\Debug\\EditStreamCallBack.dll");
addr = (int)GetProcAddress(module, (LPCSTR)"EditStreamCallBack");
flag = 1;
}
return TRUE;
}
__declspec(dllexport) void _stdcall SetText(char * str)
{
int sz = strlen(str);
memcpy(sharedStr, str, sz);
}
__declspec(dllexport) HMODULE _stdcall GetModuleH()
{
return module;
}
__declspec(dllexport) int _stdcall GetAddr()
{
return addr;
}
__declspec(dllexport) char * _stdcall GetRichTextBoxString()
{
return sharedRichTextBoxString;
}
__declspec(dllexport) int CALLBACK EditStreamCallBack(DWORD dwCookie, LPBYTE buf, DWORD numByte, DWORD* cb)
{
if(dwCookie==1) //if 1, then we want it to work for EM_STREAMIN
{
memcpy(buf, sharedStr, strlen(sharedStr));
*cb = strlen(sharedStr);
}
else if(dwCookie==2) //if 2, then we want it to work for EM_STREAMOUT
{
memcpy(sharedRichTextBoxString, buf, numByte);
}
return 0;
}
最佳答案
我发现你使用的代码示例不是最好的,它写得很脏。不过,因为您写道当前的主要问题是 C/C++ 代码,所以我建议您遵循以下内容:
- 替换
GetModuleHandle
至GetModuleHandleA
在 C/C++ 代码中。您还可以更改项目的设置以避免使用“使用 Unicode 字符集”设置。 - 向您的 C/C++ 项目添加一个新文件
EditStreamCallBack.def
(在“源文件”的上下文菜单中使用“添加”/“新项目”并选择“模块定义文件(.def)”)。作为 def 文件的包含,您应该使用以下文本
LIBRARY "EditStreamCallBack"
EXPORTS
SetText
GetModuleH
GetAddr
GetRichTextBoxString
EditStreamCallBack
EditStreamCallBack.def
的用法将解决您当前的错误问题:“找不到 GetAddr() 的合适入口点”。
因为您的 C/C++ 代码不使用 Unicode,所以您不应该忘记使用 CharSet.Ansi
在SetText
的互操作声明中和GetRichTextBoxString
EditStreamCallBack.dll
的功能。使用SendMessageA
也很重要而不是SendMessageW
用于发送消息EM_STREAMOUT
.
再补充一点。 GetModuleHandle
中dll的完整文件名的使用是允许的,但大多数情况下并不真正需要。因此,如果您不加载具有相同文件名但不同路径的同一 dll 的两个不同版本,我建议您从 C++ 程序的代码中删除 DLL 的完整路径。
已更新:我在 http://www.ok-soft-gmbh.com/ForStackOverflow/EditStreamCallBack1.zip 下发布树项目:EditStreamCallBack(内部包含 EditStreamCallBack.sln),用于创建 DLL,CSharpTest 使用简单的 C# 测试从 C# 加载 DLL,以及 CSharpTestFull。 CSharpTestFull 项目主要包含您发布的代码。
为了能够测试包含 DLL 注入(inject)的 CSharpTestFull 项目,您应该“以管理员身份”启动 Visual Studio 2010。
我在你的代码中修改的是:
-
GetWindowThreadProcessId
和OpenProcess
最后一个参数声明为int dwProcessId
. - 已插入
app.manifest
其中包含<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
。这是在管理权限下启动 .NET 应用程序所必需的,需要能够以完全访问权限打开另一个进程 (PROCESS_ALL_ACCESS
)。至少权利PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE
确实需要。
对于测试,我使用了 WordPad.exe。因为当前在您的代码中仅使用 DLL 注入(inject)和调用 GetAddr
功能和其他带有Windows的应用程序就可以了。该程序产生如下输出
GetAddr() returns 1360728224 (0x511B10A0)
inject() returns 34406400 (0x20D0000)
尊重Process Explorer (启动者也是管理员)我可以验证DLL是否确实加载到地址0x511A0000下的WordPad.exe进程中。所以您发布给我的当前代码可以工作。
我之前是怎么写的,整个代码只能看作是概念验证的代码。
关于c# - 使用 C# 的 EditStreamCallback,从 C++ 迁移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3509598/