Andrew
Andrew

Reputation: 658

MT4 DLL / TA-LIB Linker errors

This is my second attempt at a C++ program so I'm still learning.

I'm trying to create a DLL to work with Metatrader 4 which uses the ta-lib technical analysis library using Visual Studio 2013 Community.

However, when I build the solution I get the following linker errors and I don't know how to fix them.

Error   4   error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z) already defined in libcmt.lib(typinfo.obj)   C:\Users\Documents\Visual Studio 2013\Projects\iDEMA\iDEMA\MSVCRT.lib(ti_inst.obj)  iDEMA
Error   5   error LNK2005: "private: class type_info & __thiscall type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) already defined in libcmt.lib(typinfo.obj) C:\Users\Documents\Visual Studio 2013\Projects\iDEMA\iDEMA\MSVCRT.lib(ti_inst.obj)  iDEMA
Error   2   error LNK2005: _free already defined in libcmt.lib(free.obj)    C:\Users\Documents\Visual Studio 2013\Projects\iDEMA\iDEMA\MSVCRT.lib(MSVCR120.dll) iDEMA
Error   3   error LNK2005: _malloc already defined in libcmt.lib(malloc.obj)    C:\Users\Documents\Visual Studio 2013\Projects\iDEMA\iDEMA\MSVCRT.lib(MSVCR120.dll) iDEMA
Warning 1   warning LNK4098: defaultlib 'MSVCRT' conflicts with use of other libs; use /NODEFAULTLIB:library    C:\Users\Documents\Visual Studio 2013\Projects\iDEMA\iDEMA\LINK iDEMA
Error   7   error LNK1169: one or more multiply defined symbols found   C:\Users\Documents\Visual Studio 2013\Projects\iDEMA\Release\iDEMA.dll  iDEMA
Error   6   error LNK2005: _DllMain@12 already defined in uafxcw.lib(dllmodul.obj)  C:\Users\Documents\Visual Studio 2013\Projects\iDEMA\iDEMA\* CIL library *(* CIL module *)  iDEMA

My header file is this

// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the IDEMA_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// IDEMA_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.

#ifdef IDEMA_EXPORTS
#define IDEMA_API __declspec(dllexport)
#else
#define IDEMA_API __declspec(dllimport)
#endif

#pragma pack(push,1)
struct RateInfo
{
    __int64           ctm;
    double            open;
    double            low;
    double            high;
    double            close;
    unsigned __int64  vol_tick;
    int               spread;
    unsigned __int64  vol_real;
};
#pragma pack(pop)

enum ENUM_PRICE
{
    PRICE_OPEN,
    PRICE_LOW,
    PRICE_HIGH,
    PRICE_CLOSE
};

// This class is exported from the iDEMA.dll
class IDEMA_API CiDEMA {
public:
    CiDEMA(void);
    double iDEMA(RateInfo, int, int, int, ENUM_PRICE);
};

extern IDEMA_API int niDEMA;

IDEMA_API int fniDEMA(void);

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <string>
#include "C:\ta-lib-0.4.0-msvc\ta-lib\c\include\ta_libc.h"

#pragma once

#ifndef __AFXWIN_H__
#error "include 'stdafx.h' before including this file for PCH"
#endif

#include "resource.h"       // main symbols

And my code is this

// iDEMA.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "iDEMA.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

#define WIN32_LEAN_AND_MEAN
#define MT4_EXPFUNC __declspec(dllexport)

using namespace std;

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    //---
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    //---
    return(TRUE);
}

MT4_EXPFUNC double __stdcall iDEMA(const RateInfo* rates, const int rates_total, const int period, const int shift, const ENUM_PRICE applied_price)
{
    //---
    if (rates == NULL)
    {
        printf("iDEMA: NULL array\n");
        return(0.0);
    }
    //---
    if (rates_total<0 || rates_total<2 * period)
    {
        printf("iDEMA: wrong rates_total number (%d)\n", rates_total);
        return(0.0);
    }
    //---
    if (period<2 || period>100000)
    {
        printf("iDEMA: wrong period number (%d)\n", period);
        return(0.0);
    }
    //---
    if (shift<0 || shift >= rates_total)
    {
        printf("iDEMA: wrong shift number (%d)\n", shift);
        return(0.0);
    }
    //---
    if (applied_price<0 || applied_price>3)
    {
        printf("iDEMA: wrong applied price (%d)\n", applied_price);
        return(0.0);
    }
    //---

    TA_RetCode retCode;
    retCode = TA_Initialize();

    if (retCode != TA_SUCCESS)
    {
        printf("TA_LIB initialistion failed (%d)!\n", retCode);
        return(0.0);
    }

    vector<TA_Real> dataArray;
    const TA_Real* dataArray_c_pointer = dataArray.data();

    // DEMA = ( 2 * EMA(n)) - (EMA(EMA(n)) ), where n= period

    for (int nitem = rates_total - 1 - shift - (2 * period); nitem < rates_total - 1 - shift; nitem++)
    {
        TA_Real value = 0.0;

        switch (applied_price)
        {
        case PRICE_OPEN: value = rates[nitem].open; break;
        case PRICE_LOW: value = rates[nitem].low; break;
        case PRICE_HIGH: value = rates[nitem].high; break;
        case PRICE_CLOSE: value = rates[nitem].close; break;
        }

        dataArray[nitem] = value;
    }

    TA_Integer outBegin = 0, outElements = 0;

    int beginIndx, endIndx;
    beginIndx = endIndx = dataArray.size() - 1;
    int array_size = endIndx - beginIndx + 1;
    cout << "beginIndx = " << to_string(beginIndx) << endl << "endIndx = " << to_string(endIndx) << endl << "array_size = " << to_string(array_size) << endl;

    vector<TA_Real> outDema(array_size, 0.0);
    TA_Real* outDema_c_pointer = outDema.data();

    retCode = TA_DEMA(beginIndx, endIndx, dataArray_c_pointer, period, &outBegin, &outElements, outDema_c_pointer);

    double value = 0.0;

    if (retCode == TA_SUCCESS)
    {
        cout << "outBegin = " << outBegin << " outElements = " << outElements << endl;
        int  lastElement = outElements - 1;;
        cout << "outDema.at(" << to_string(lastElement) << ") = " << to_string(outDema.at(lastElement)) << endl;

        delete dataArray_c_pointer;
        delete outDema_c_pointer;

        value = outDema.at(lastElement);
    }

    retCode = TA_Shutdown();

    return value;
}

I installed the library using nuGet.

Could you help to compile this DLL please.

Thanks in advance.

Update 10/10/15

I removed the package nuGet and used static linking from a different directory.

I'm now getting these linker errors:

Error   2   error LNK1169: one or more multiply defined symbols found   C:\Users\Documents\Visual Studio 2013\Projects\iDEMA\Release\iDEMA.dll  iDEMA
Error   1   error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodul.obj)    C:\Users\Documents\Visual Studio 2013\Projects\iDEMA\iDEMA\* CIL library *(* CIL module *)  iDEMA

Still don't understand how to fix them!

Any help will be appreciated.

Thanks.

Upvotes: 0

Views: 801

Answers (2)

Andrew
Andrew

Reputation: 658

Managed to get it to link after modifying the header and source files. Here's the final result:

// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the IDEMA_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// IDEMA_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.

#define WIN32_LEAN_AND_MEAN
#define MT4_EXPFUNC __declspec(dllexport)

#pragma pack(push,1)
struct RateInfo
{
    __int64           ctm;
    double            open;
    double            low;
    double            high;
    double            close;
    unsigned __int64  vol_tick;
    int               spread;
    unsigned __int64  vol_real;
};

enum ENUM_PRICE
{
    PRICE_OPEN,
    PRICE_LOW,
    PRICE_HIGH,
    PRICE_CLOSE
};
#pragma pack(pop)

// This class is exported from the iDEMA.dll
class MT4_EXPFUNC CiDEMA {
public:
    CiDEMA(void);
    double iDEMA(RateInfo, int, int, int, ENUM_PRICE);
};

extern MT4_EXPFUNC int niDEMA;

MT4_EXPFUNC int fniDEMA(void);

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <string>
#include "C:\ta-lib-0.4.0-msvc\ta-lib\c\include\ta_libc.h"

#pragma once

#ifndef __AFXWIN_H__
#error "include 'stdafx.h' before including this file for PCH"
#endif

#include "resource.h"       // main symbols

And the source file:

// iDEMA.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "iDEMA.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

using namespace std;

MT4_EXPFUNC double __stdcall iDEMA(const RateInfo* rates, const int rates_total, const int period, const int shift, const ENUM_PRICE applied_price)
{
    //---
    if (rates == NULL)
    {
        printf("iDEMA: NULL array\n");
        return(0.0);
    }
    //---
    if (rates_total<0 || rates_total<2 * period)
    {
        printf("iDEMA: wrong rates_total number (%d)\n", rates_total);
        return(0.0);
    }
    //---
    if (period<2 || period>100000)
    {
        printf("iDEMA: wrong period number (%d)\n", period);
        return(0.0);
    }
    //---
    if (shift<0 || shift >= rates_total)
    {
        printf("iDEMA: wrong shift number (%d)\n", shift);
        return(0.0);
    }
    //---
    if (applied_price<0 || applied_price>3)
    {
        printf("iDEMA: wrong applied price (%d)\n", applied_price);
        return(0.0);
    }
    //---

    TA_RetCode retCode;
    retCode = TA_Initialize();

    if (retCode != TA_SUCCESS)
    {
        printf("TA_LIB initialistion failed (%d)!\n", retCode);
        return(0.0);
    }

    vector<TA_Real> dataArray;
    const TA_Real* dataArray_c_pointer = dataArray.data();

    // DEMA = ( 2 * EMA(n)) - (EMA(EMA(n)) ), where n= period

    for (int nitem = rates_total - 1 - shift - (2 * period); nitem < rates_total - 1 - shift; nitem++)
    {
        TA_Real value = 0.0;

        switch (applied_price)
        {
        case PRICE_OPEN: value = rates[nitem].open; break;
        case PRICE_LOW: value = rates[nitem].low; break;
        case PRICE_HIGH: value = rates[nitem].high; break;
        case PRICE_CLOSE: value = rates[nitem].close; break;
        }

        dataArray[nitem] = value;
    }

    TA_Integer outBegin = 0, outElements = 0;

    int beginIndx, endIndx;
    beginIndx = endIndx = dataArray.size() - 1;
    int array_size = endIndx - beginIndx + 1;
    cout << "beginIndx = " << to_string(beginIndx) << endl << "endIndx = " << to_string(endIndx) << endl << "array_size = " << to_string(array_size) << endl;

    vector<TA_Real> outDema(array_size, 0.0);
    TA_Real* outDema_c_pointer = outDema.data();

    retCode = TA_DEMA(beginIndx, endIndx, dataArray_c_pointer, period, &outBegin, &outElements, outDema_c_pointer);

    double value = 0.0;

    if (retCode == TA_SUCCESS)
    {
        cout << "outBegin = " << outBegin << " outElements = " << outElements << endl;
        int  lastElement = outElements - 1;;
        cout << "outDema.at(" << to_string(lastElement) << ") = " << to_string(outDema.at(lastElement)) << endl;

        delete dataArray_c_pointer;
        delete outDema_c_pointer;

        value = outDema.at(lastElement);
    }

    retCode = TA_Shutdown();

    return value;
}

Upvotes: 1

user5000935
user5000935

Reputation:

Try wrapping your header like this:

extern "C"
{
   #include "stdafx.h"
   #include "iDEMA.h"
}

If VS complains about the extern keyword go to Project Properties > C/C++ > Advanced > Compile As and check Compile as C++.

For the Updated answer, it looks like your compiler is seeing two definitions of the same symbol.

Try using

#include <stdafx.h>
#include <iDEMA.h>

They look in different places. If it doesn't help, try the extern "C" with your old project (before update 10/10/15).

Maybe you've added some dll or lib to your PATH in your first try and after the "Update 10/10/15", you don't need them anymore.

Also read this answer and this MSDN Building Visual C++ page.

Edit: If possible, create a new project. Maybe, in your attempts, you've messed something.

Upvotes: 2

Related Questions