c# - 使用 C# 的 EditStreamCallback,从 C++ 迁移

标签 c# c++

我正在尝试完成与这里所做的大致相同的事情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++ 代码,所以我建议您遵循以下内容:

  • 替换GetModuleHandleGetModuleHandleA在 C/C++ 代码中。您还可以更改项目的设置以避免使用“使用 Unicode 字符集”设置。
  • 向您的 C/C++ 项目添加一个新文件 EditStreamCallBack.def (在“源文件”的上下文菜单中使用“添加”/“新项目”并选择“模块定义文件(.def)”)。作为 def 文件的包含,您应该使用以下文本

LIBRARY "EditStreamCallBack"

EXPORTS
    SetText
    GetModuleH
    GetAddr
    GetRichTextBoxString
    EditStreamCallBack

EditStreamCallBack.def的用法将解决您当前的错误问题:“找不到 GetAddr() 的合适入口点”。

因为您的 C/C++ 代码不使用 Unicode,所以您不应该忘记使用 CharSet.AnsiSetText的互操作声明中和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。

我在你的代码中修改的是:

  1. GetWindowThreadProcessIdOpenProcess最后一个参数声明为 int dwProcessId .
  2. 已插入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/

相关文章:

c# - 在 ASP MVC 3 中创建可下载的文本文件时无法访问已关闭的流

c++ - 如何处理具有相同方法的不同类?

c++ - 如何使用 optarg 获取多个值?

c++ - 如何在 TabCtrl 内的子对话框中将焦点设置到 CEdit?

c# - 在对子类使用 'dynamic' (C#) 时,.NET 4 如何决定调用哪个方法?

c# - 使用 SharpAvi 将图像转换为视频

c# - Windows服务线程与循环和WCF

c++ - 围绕另一个对象旋转对象

c++ - 如何使用 Intel PIN 获取内存操作值?

c# - 如果修改了详细实体,为什么 EntityFramework 会更新主从关系中的主实体?