在C ++中设置一个模拟接口

我目前正在尝试使用一个特定的SDK,我有一个供应商提供的DLL加载函数..我必须传递参数到这些函数和DLL所有的工作..

现在,DLL应该是与另一个设备进行通信,而我只是等待结果。 但是,我没有这个设备,那么如何设置一个模拟接口来模拟设备呢?

要清楚,这里是一个例子:

myfuncpointer.Open(someparam,anotherparam,...); 

现在,因为我没有这个设备,DLL实际上不能执行上面的function; 它失败。 如何设置testing,以便DLL与我devise的类而不是设备对话? 有什么办法来redirectDLL的调用?

我如何使DummyDevice类来做到这一点?

谢谢..

PS如果有什么不清楚,请不要太快downvote ..评论至于我需要解释,我会尽力清除它..谢谢。


编辑:但是,我有什么是所有使用的数据结构和它必须包含的预期/合法值的规格表。 所以例如,如果我调用一个函数:

 myfuncpointer.getinfo(param,otherparam); 

其中一个参数是一个数据结构,DLL查询设备后填充的信息(比如,如果选项启用)..我可以做到这一点

 param.option = true; 

在完成getinfo调用之后。

这是testing代码的好方法吗? 诱骗这个DLL思考所有错误的东西似乎是非常非常危险的,似乎真的很难缩放,甚至只是一点点。

仿真设备访问权限解决方案,直到你得到硬件? 如果是这样的话,我建议找一些其他方法来提高生产力:在其他方面工作,编写单元测试等等。

模拟设备是否是永久性的需求? 如果是这样,这里有几个你可以采取的方法:

  1. 如果其他供应商的SDK具有“模拟”或“仿真”模式,请使用它。 你可能会感到惊讶。 如果没有安装其他供应商的硬件,您可能不是唯一需要测试/运行应用程序的客户端。

  2. 把另一个供应商的代码拿出来。 只模仿您的应用程序需要的功能,并根据您的程序的要求。 一切都在你的控制之下。

    一个。 添加一个间接层。 使用多态性在两个实现之间切换:一个调用另一个供应商的DLL,另一个模拟其行为。 将代码调用到抽象基类中而不是直接调用另一个供应商的DLL也会使编写单元测试更容易。

    写一个模拟DLL(如Adam Rosenfield所建议的)。 您需要精确匹配函数名称和调用约定。 当您升级到其他供应商的DLL的新版本时,您将需要扩展模拟DLL以支持您的应用程序使用的任何新的入口点。

    如果你需要选择在运行时使用哪个DLL,这可能需要转换你的代码来动态地加载DLL(但是听起来好像你可能已经这样做了,因为你说了一些关于函数指针的东西)。 您可以在安装时决定是否安装其他供应商的DLL或模拟DLL。 如果这纯粹是为了测试的目的,那么你可以选择在编译时使用哪个DLL,然后构建两个版本的应用程序。

  3. 写一个模拟设备驱动程序(如其他人所建议的)。

    如果您有其他供应商的用户模式DLL与其设备驱动程序之间的接口规范,则可能是可行的。 即使你是一位有经验的设备驱动程序开发人员,尤其是如果你没有其他供应商的DLL的源代码,也可能需要比其他方法更长的时间。 UMDF(用户模式驱动程序框架)可能会使这一点稍微简单或耗时较少。

    如果您提到的规范没有描述用户/内核接口,则需要对该接口进行逆向工程。 与其他选项相比,这可能不会有效地利用您的时间,特别是在驱动程序接口非常复杂的情况下(例如,它将大量复杂的数据结构传递给DeviceIoControl() )。

    在这两种情况下,每次升级到其他供应商的SDK的新版本时都需要重新访问。 相同的导出DLL函数可能需要使用新的DeviceIoControl()代码和结构。

这取决于DLL如何访问设备。 如果通过调用另一个DLL中的函数来实现,则可以提供一个模拟DLL,替换适当的函数。 但是,如果DLL正在做一些低层次的事情,比如直接调用内核,那么将会有更艰难的时间。 在这种情况下,你可能必须写一个新的设备驱动程序或内核扩展或其他东西。

有很多地方可以插入一个模拟对象:

  1. 模拟对DLL的调用 :在你的应用程序中,编写一个封装函数指针调用的Facade / wrapper类到供应商的DLL中。 总的来说这是一个好主意,因为你可以在DLL函数调用中放置一个更干净的类API。

  2. 模拟DLL :编写你自己模拟的DLL

  3. 模拟设备 :写一个模拟设备的设备驱动程序。 我不会推荐这个,因为这将是很多工作,模拟设备的行为(包括错误和怪癖)将是困难的。

我会推荐#1,因为它是最少量的工作,它不是丢弃代码。

您设计的Facade类接口将调用隐藏到供应商的DLL中将改进其他代码的设计。 它将减少您的代码与供应商的DLL和API的低级实现细节的耦合。 如果供应商提供新的DLL API,则可以更轻松地将其与代码集成在一起。 您甚至可以用另一个供应商或设备替换该供应商的DLL。 🙂

你可能必须为此写一个设备驱动程序。 根据您的平台,您可能有可用的设备可能适合您(即Linux中的'lo'界面等)。

你不是第一个有这个问题的人,所以一定要在滚动你自己的网站前冲刷网络:-)

如果DLL正在与外部硬件设备进行通信,则需要实现与实际驱动程序兼容的驱动程序,但需要模拟响应。

最有可能的是,如果你没有这个设备,那么这个SDK将毫无用处。 如果提供了一些与外部设备无关的功能,那么在没有硬件依赖性的情况下获取等价库几乎肯定会更容易。

我在WIN32环境中使用了一个相对比较冒险的,不可移植的方法来模拟函数(我认为它只有32位,但是不确定)。 这里是:

 #define INJECTED_BYTES 5 static void replace_target(void *Target, void *server) { DWORD dwOld; VirtualProtect(Target, INJECTED_BYTES, PAGE_WRITECOPY, &dwOld); *((unsigned char *)Target)++ = 0xe9 ; // jump relative *(unsigned int *)Target = (unsigned int)((unsigned char *)server - (unsigned char *)Target)-4; VirtualProtect(((unsigned char *)Target)-1, INJECTED_BYTES, PAGE_EXECUTE, &dwOld); FlushInstructionCache(GetCurrentProcess(), 0, 0); } 

它所做的就是将目标函数的前几个字节替换为模拟函数的跳转。 所以当你调用目标时,它直接跳到你的存根。 只要记住要保留被替换的字节(INJECTED_BYTES)的副本,以便以后可以撤消你的模拟。

来想一想,什么阻止你写自己的DLL,只有残留什么真正的DLL做?