контекст
Я работаю над проектом, предназначенным для отправки определенных команд на устройство. Каждое устройство может быть сопряжено с dll (например, deviceADll.h, deviceBDll.h), и я не запрограммировал dll, и я не могу изменять их каким-либо образом. Я отвечаю за интеграцию DeviceB в проект с минимальными изменениями в структуре проекта. Я знаю, что структура не может быть оптимальной и / или хорошо спроектированной, поэтому я готов принять предложение по этому вопросу в качестве последнего средства решения.
Поскольку устройства очень похожи, все функции Dll имеют одинаковое имя и часто один и тот же прототип.
Также из-за этого я создал родительский класс (Device_ts.h), от которого наследуются DeviceA_ts.h и DeviceB_ts.h (у меня также есть фабричный класс для устройств, но я не думаю, что он имеет отношение к моей проблеме) ,
проблема
Проблема возникает, когда я пытаюсь включить оба Dlls: проект компилируется, но я получаю
Warning 60 warning LNK4006: Connect@12 already defined in DeviceA.lib(DeviceA.dll); second definition ignored C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name
с последующим
Warning 61 warning LNK4006: __imp__Connect@12 already defined in DeviceA.lib(DeviceA.dll); second definition ignored C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name
и
Warning 62 warning LNK4221: This object file does not define any previously undefined public symbols, so it will not be used by any link operation that consumes this library C:\project_path\DeviceB.lib(DeviceB.dll) Project_Name
Кто-нибудь сталкивался с подобной ситуацией? Должен ли я игнорировать эти предупреждения или я не смогу позвонить DeviceB.h
функции, так как их определения игнорируются?
Я использую Visual Studio 2010, Device_ts.h
Библиотека, которую я пишу, является статической библиотекой, и все параметры проекта (например, / MD, включая каталоги, зависимости, MFC и т. д.) установлены правильно, исходя из того, что я нашел в своем исследовании этой проблемы.
Код
Код include и выглядит следующим образом (я покажу только одну из функций, вызывающих предупреждение, поскольку я получаю ту же ошибку для 50 функций):
DeviceADll.h
#ifndef DEVICEA_H__
#define DEVICEA_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
namespace DeviceA
{
// some struct definition that don't cause the linker warnings
//...
// function definitions
extern "C" HANDLE PASCAL EXPORT Connect( HANDLE h_devA, const char *ip);
// ...
} // namespace DeviceA
DeviceBDll.h
#ifndef DEVICEB_H__
#define DEVICEB_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
namespace DeviceB
{
// some struct definition that don't cause the linker warnings
//...
// function definitions
extern "C" HANDLE PASCAL EXPORT Connect( HANDLE h_devB, const char *ip);
// ...
} // namespace DeviceB
Device_ts.h
#ifndef DEVICE_FCT_H_
#define DEVICE_FCT_H_
#ifndef EXPORT
#define EXPORT
#endif
#if _MSC_VER > 1000
#pragma once
#endif
#include "DeviceADll.h"#include "DeviceBDll.h"
class CDevice {
public:
virtual BOOL Connect(char *ip_addr) = 0;
};
#endif DEVICE_FCT_H_
Это хороший вариант использования для ручной загрузки DLL, используя LoadLibrary()
а также GetProcAddress()
,
Вам придется управлять указателем на функцию для каждой функции, которая выглядит таким образом, что немного болезненно, но обход загрузки DLL в ОС дает вам большую гибкость.
Также обратите внимание, что вам не нужно ссылаться на DLL при использовании этого метода, привязка dll составляет 100% времени выполнения, а компоновщик вообще не задействован.
Вот пример:
typedef void (*connect_fn)(HANDLE, const char*);
connect_fn connect_a;
connect_fn connect_b;
int main()
{
HINSTANCE dll_a = LoadLibrary("path_to_dll_a.dll");
HINSTANCE dll_b = LoadLibrary("path_to_dll_b.dll");
if (!dll_a || !dll_b) {
return 1;
}
connect_a = (connect_fn)GetProcAddress(dll_a , "Connect");
connect_b = (connect_fn)GetProcAddress(dll_b , "Connect");
// connect_a and connect_b can now be used.
return 0;
}
Редактировать: По сути, я предлагаю вам рассматривать библиотеки устройств как плагины, а не как динамические библиотеки.
Других решений пока нет …