Настройка макета интерфейса в C ++ - PullRequest
1 голос
/ 24 февраля 2009

В настоящее время я пытаюсь использовать определенный SDK, который загружает функции из библиотеки DLL, предоставляемой поставщиком. Я должен передать аргументы этим функциям, и библиотека DLL выполнит всю работу ..

Теперь предполагается, что DLL взаимодействует с другим устройством, а я просто жду результатов. Однако у меня нет этого устройства, так как я могу настроить макет интерфейса для эмуляции устройства?

Для ясности, вот пример:

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

Теперь, поскольку у меня нет устройства, DLL фактически не может выполнять вышеуказанную функцию; это терпит неудачу. Как настроить тестирование так, чтобы DLL взаимодействовала с классом, который я разработала, а не с устройством? Есть ли способ перенаправить вызов DLL?

Как мне сделать класс DummyDevice для этого?

Спасибо ..

P.S. Если что-то не понятно, пожалуйста, не спешите опровергать ... Прокомментируйте, что мне нужно объяснить, и я постараюсь прояснить это. Спасибо.


РЕДАКТИРОВАТЬ: Тем не менее, у меня есть спецификация со всеми используемыми структурами данных и ожидаемыми / допустимыми значениями, которые она должна содержать. Так, например, если я вызываю функцию:

myfuncpointer.getinfo(param,otherparam);

где один из параметров - это структура данных, которую DLL заполняет информацией (скажем, если опция включена) после запроса устройства .. Я могу сделать это

param.option = true;

после завершения вызова getinfo.

Это хороший способ проверить код? Кажется очень и очень опасным обманывать эту DLL, заставляя ее думать обо всех неправильных вещах, и кажется, что ее действительно очень трудно масштабировать хотя бы немного ..

Ответы [ 6 ]

6 голосов
/ 24 февраля 2009

Доступ к эмулируемому устройству ограничен до тех пор, пока вы не получите аппаратное обеспечение? Если это так, я рекомендую найти какой-то другой способ быть продуктивным: работать над чем-то другим, писать модульные тесты и т. Д.

Постоянно ли требуется доступ к эмулируемому устройству? Если это так, вот несколько подходов, которые вы могли бы предпринять:

  1. Если SDK другого поставщика имеет режим «симуляции» или «эмуляции», используйте его. Возможно, вы удивитесь. Вы, вероятно, не единственный клиент, который должен иметь возможность протестировать / запустить свое приложение без установленного оборудования другого поставщика.

  2. Уберите код другого поставщика из картинки. Эмулируйте только ту функциональность, которая требуется вашему приложению, и основывайте ее на требованиях вашей программы. Все под вашим контролем.

    а. Добавьте слой косвенности. Используйте полиморфизм для переключения между двумя реализациями: одна, которая вызывает DLL другого вендора, и другая, эмулирующая его поведение. Наличие вашего вызова кода в абстрактном базовом классе вместо прямого вызова DLL другого производителя также облегчит написание модульных тестов для вашего кода.

    б. Напишите фиктивную DLL (как предложил Адам Розенфилд). Вам необходимо точно сопоставить имена функций и соглашения о вызовах. При обновлении до новых версий DLL другого производителя вам нужно будет расширить фиктивную DLL для поддержки любых новых точек входа, которые использует ваше приложение.

    Если вам нужно выбрать, какую DLL использовать во время выполнения, для этого может потребоваться преобразование кода для динамической загрузки DLL (но, похоже, вы уже это делаете, учитывая, что вы что-то говорили о указателях функций). Вы можете решить во время установки, устанавливать ли DLL-файл другого поставщика или фиктивную DLL. И если это исключительно для целей тестирования, вы можете выбрать, какую DLL использовать во время компиляции, и просто собрать две версии вашего приложения.

  3. Напишите драйвер фиктивного устройства (как предлагали другие).

    Если у вас есть спецификация для интерфейса между DLL пользовательского режима другого производителя и его драйвером устройства, это может быть выполнимо. Это, вероятно, займет больше времени, чем любой другой подход, даже если вы опытный разработчик драйверов устройств, особенно если у вас нет источника для DLL другого производителя. UMDF (платформа драйвера пользовательского режима) может сделать это немного проще или займет меньше времени.

    Если спецификация, которую вы упомянули, не описывает интерфейс пользователя / ядра, вам нужно будет перепроектировать этот интерфейс. Вероятно, это не будет эффективным использованием вашего времени по сравнению с другими вариантами, особенно если интерфейс драйвера сложен (например, он передает много сложных структур данных в DeviceIoControl()).

    В обоих случаях вам придется пересматривать это каждый раз при обновлении до новой версии SDK другого поставщика. Те же экспортируемые функции DLL могут потребовать использования новых DeviceIoControl() кодов и структур.

2 голосов
/ 27 февраля 2009

Есть несколько мест, где вы можете вставить макет объекта:

  1. Ложные вызовы DLL : внутри вашего приложения напишите класс Facade / wrapper , который инкапсулирует вызовы указателя функции в DLL поставщика. В общем, это хорошая идея, потому что вы можете поместить API-интерфейс более чистого класса в вызовы функций DLL.

  2. Макет DLL : напишите свою собственную DLL, которая эмулирует

  3. Макет устройства : написать драйвер устройства, который эмулирует устройство. Я не рекомендовал бы это, потому что это будет большая работа, и эмулировать поведение устройства (включая ошибки и причуды) будет трудно.

Я бы порекомендовал # 1 , потому что это наименьший объем работы и это не одноразовый код.

Интерфейс класса Facade, который вы разрабатываете, чтобы скрыть вызовы в DLL поставщика, улучшит дизайн вашего другого кода. Это уменьшит связь вашего кода с низкоуровневыми деталями реализации DLL и API вендора. Если поставщик предоставит новые API-интерфейсы DLL, вы сможете легче интегрировать его с вашим кодом. Возможно, вы даже сможете заменить DLL этого поставщика другим поставщиком или устройством. :)

2 голосов
/ 24 февраля 2009

Это зависит от того, как DLL обращается к устройству. Если это происходит путем вызова функций из другой библиотеки DLL, вы можете предоставить фиктивную библиотеку DLL, в которой вы заменили соответствующие функции. Однако, если DLL делает что-то низкоуровневое, например, вызывает прямо в ядре, у вас будет намного сложнее. В этом случае вам, вероятно, придется написать новый драйвер устройства или расширение ядра или что-то еще.

1 голос
/ 24 февраля 2009

Если DLL взаимодействует с внешним аппаратным устройством, вам необходимо реализовать драйвер, совместимый с фактическим драйвером, но с эмулируемым ответом.

Скорее всего, если у вас нет устройства, SDK все равно будет бесполезен. Если есть некоторая функциональность, которая не относится к этому внешнему устройству, почти наверняка будет проще найти эквивалентную библиотеку без аппаратной зависимости.

1 голос
/ 24 февраля 2009

Возможно, вам придется написать драйвер устройства для этого. В зависимости от вашей платформы у вас могут быть доступные устройства, которые могут работать на вас (например, такие вещи, как интерфейс «lo» в Linux).

Вы не первый человек, у которого возникла эта проблема, поэтому обязательно поищите в Интернете, прежде чем развернуть свой собственный: -)

0 голосов
/ 27 февраля 2009

Я использовал относительно хакерский, непереносимый метод для имитации функций в среде 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?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...