Использование mpusbapi.h от Microchip в VS 2015 дает «LNK2005 Уже определено». ошибки

Я пишу класс, который должен импортировать некоторые из его функций из файла mpusbapi.dll. К сожалению, когда я пытаюсь включить ActuatorControl.h в основной файл, мне выдают уже определенную ошибку LNK2005,

Error LNK2005
"unsigned long (__cdecl* MPUSBGetConfigurationDescriptor)(void *,unsigned char,void *,unsigned long,unsigned long *)" (?MPUSBGetConfigurationDescriptor@@3P6AKPAXE0KPAK@ZA)
already defined in ActuatorControl.obj
Linear Actuator
C:\Users\Edward Harsono\Desktop\Linear Actuator\Linear Actuator\Linear Actuator.obj
1

Остальные функции, которые были получены из mpusbapi.dll, получили то же сообщение. Я включил защиту для mpusbapi.h и ActuatorControl.h. Я написал этот код в Visual Studio 2015.

Mpusbapi.h и mpusbapi.dll получены от Microchip Technology Incorporated.

Может ли кто-нибудь помочь мне с этим? Я был на нем часами. Вот мой код

main.cpp

#include "stdafx.h"#include <iostream>
#include <fstream>
#include <windows.h>

#include "ActuatorControl.h"
int main()
{
ActuatorControl x;
return 0;
}

ActuatorControl.h

#pragma once
#ifndef _ActuatorControl_H_
#define _ActuatorControl_H_

#include "stdafx.h"#include <fstream>
#include <iostream>
#include <windows.h>
#include <Dbt.h>
#include <tchar.h>

#include "mpusbapi.h"
class ActuatorControl {
private:
//----------------Global variables used in this application--------------------------------

public:
ActuatorControl();
~ActuatorControl();
};

#endif

ActuatorControl.cpp

#include "ActuatorControl.h"
ActuatorControl::ActuatorControl() {
HMODULE DLL = LoadLibrary(L"mpusbapi.dll");
if (DLL) {
MPUSBGetDLLVersion = (DWORD(*)(void)) GetProcAddress(DLL, "_MPUSBGetDLLVersion");

}
}

ActuatorControl::~ActuatorControl() {

}

0

Решение

Итак, я взглянул на mpusbapi.h и пример приложения (отсюда, MCHPFUSB 1.3).

Я предполагаю, что вы динамически загружаете функции во время выполнения с LoadLibrary, кажется, что их двоичные файлы были собраны с помощью компилятора Borland, и, таким образом, заглушка LIB не будет работать как есть в VS (если у вас нет сборки VS или вы хотите просто создать его вручную).


Краткий ответ: заголовок «как есть» на самом деле не подходит для включения из нескольких файлов. Это вроде работает в их простых примерах приложений, но это все, так что вам придется свернуть свои собственные. Несмотря на последствия их «документации», для поддержания вашего здравомыслия вы захотите просмотреть mpusbapi.h как более пример чем что-либо вообще полезное.


Средний ответ: заголовок действительно плохо спроектирован. В частности, он определяет глобальные переменные, поэтому каждый исходный файл, который включает его, будет иметь те, которые определены, и, следовательно, ваша ошибка. Причина, по которой им это сошло с рук, заключается в следующем: они создали все с помощью инструментов Borland, вероятно, включая их примеры, и в отличие от большинства других компиляторов, множественные определения — просто предупреждение с компоновщиком Borland. Таким образом, они, вероятно, проигнорировали предупреждения, так как это все еще работал. Теперь вы платите цену, когда используете Saner Linker. (Кроме того, библиотека очень старая, я не помню, что VS делал с несколькими определениями в 2004 году или когда-либо, поэтому также возможно, что раньше это принимали.)


Длинный ответ / решение таково: вещи в этом заголовке не являются объявлениями функций или typedefs, это фактические определения переменных указателей на функции (которые вы ответственны за инициализацию с помощью GetProcAddress). У вас есть много вариантов, но в основном вы просто захотите начать с нуля, используя в качестве руководства сигнатуры функций, приведенные в текущем заголовке.

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

void LoadDLL(void)
{
libHandle = NULL;
libHandle = LoadLibrary("mpusbapi");
if(libHandle == NULL)
{
printf("Error loading mpusbapi.dll\r\n");
}
else
{
MPUSBGetDLLVersion=(DWORD(*)(void))\
GetProcAddress(libHandle,"_MPUSBGetDLLVersion");
MPUSBGetDeviceCount=(DWORD(*)(PCHAR))\
GetProcAddress(libHandle,"_MPUSBGetDeviceCount");
MPUSBOpen=(HANDLE(*)(DWORD,PCHAR,PCHAR,DWORD,DWORD))\
GetProcAddress(libHandle,"_MPUSBOpen");
MPUSBWrite=(DWORD(*)(HANDLE,PVOID,DWORD,PDWORD,DWORD))\
GetProcAddress(libHandle,"_MPUSBWrite");
MPUSBRead=(DWORD(*)(HANDLE,PVOID,DWORD,PDWORD,DWORD))\
GetProcAddress(libHandle,"_MPUSBRead");
MPUSBReadInt=(DWORD(*)(HANDLE,PVOID,DWORD,PDWORD,DWORD))\
GetProcAddress(libHandle,"_MPUSBReadInt");
MPUSBClose=(BOOL(*)(HANDLE))GetProcAddress(libHandle,"_MPUSBClose");

if((MPUSBGetDeviceCount == NULL) || (MPUSBOpen == NULL) ||
(MPUSBWrite == NULL) || (MPUSBRead == NULL) ||
(MPUSBClose == NULL) || (MPUSBGetDLLVersion == NULL) ||
(MPUSBReadInt == NULL))
printf("GetProcAddress Error\r\n");
}//end if else
}//end LoadDLL

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

Итак (и опять-таки при условии ручного связывания во время выполнения, если у вас есть библиотека VSB, вы можете просто пропустить все это, связать с LIB и включить _mpusbapi.h [обратите внимание на подчеркивание] но не mpusbapi.h).

Теперь, как я уже сказал, вариантов много, но у них у всех одинаковые цели:

  • Определите эти функциональные указатели один раз.
  • декларировать их в заголовке, чтобы вы могли использовать их в другом месте (mpusbapi.h совершает ошибку определяющий их в шапке).
  • Когда ваша программа запустится, заполните указатели функций LoadLibrary/GetProcAddress как в LoadDLL() реализация выше.

Так что делай все, что плавает на твоей лодке. Вот один быстрый и грязный способ выполнить работу:

  1. Создайте какой-нибудь исходный файл (возможно, тот же, что вы положили LoadDLL() или эквивалент в) и копировать + вставить все эти определения указателей на функции из текущего mpusbapi.h внутрь. Этот источник находится сейчас, где будут определены эти глобальные переменные.
  2. редактировать mpusbapi.h и добавить extern перед каждым определением, так что оно просто становится декларацией, например:

    extern DWORD (*MPUSBGetDeviceCount)(PCHAR pVID_PID);
    
  3. Теперь вы можете включить свой фиксированный mpusbapi.h везде, где вам нужно использовать их.

  4. Будь уверен и позвони LoadDLL() или что с LoadLibrary/GetProcAddress загрузить и инициализировать все ваши глобальные указатели на функции один раз, прежде чем использовать какой-либо из них.

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

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]