0

I've got an issue with my program, I'm working with Embarcadero XE8 C++ builder for 32 bit.

When I want to use a method to read/write stuff to a PLC (programmable logic controller, mostly used for communicating with machines) I get an object that is NULL.

I simply have a Main form where I want to create the connection to the PLC.

In my main I have this:

static CEasyPLCHandler *pPLCHandler;

in a method on the same page I have:

long ReadWriteTest(void)
{
unsigned long ulStart;
PlcSymbolDesc *pSymbols;
unsigned long ulNumOfSymbols = 0;
int iNumOfVars = 2;
int i;
char **ppszVars = new char*[iNumOfVars];

for (i=0; i< iNumOfVars; i++)
    ppszVars[i] = new char[255];

long lResult = RESULT_FAILED;
lResult = pPLCHandler->GetAllItems(&pSymbols, &ulNumOfSymbols);
if (lResult == RESULT_OK)

When I debug, It shows pPLCHandler = NULL

When I check out where CEasyPLCHandle comes from, I come to a page (which I included from a library) and see these lines:

class PLCH_DLL_DECL CEasyPLCHandler : public CPLCHandler
{
public:
    CEasyPLCHandler(RTS_HANDLE hLogFile = RTS_INVALID_HANDLE);
    CEasyPLCHandler(PlcConfig *pPlcConfig, PlcDeviceDesc *pDeviceDesc, RTS_HANDLE hLogFile = RTS_INVALID_HANDLE);
    CEasyPLCHandler(unsigned long ulId, char *pszIniFile, RTS_HANDLE hLogFile = RTS_INVALID_HANDLE);
    CEasyPLCHandler(char *pszPlcName, char *pszIniFile, RTS_HANDLE hLogFile = RTS_INVALID_HANDLE);
    virtual ~CEasyPLCHandler(void);

    // See PLCConfig.h for defines of pszProtocol
    // e.g. #define PLCC_DN_TCPIP_L2ROUTE   "Tcp/Ip (Level 2 Route)"
    virtual long ConnectTcpipViaGateway(char *pszGatewayIP, char *pszPlcIP, char *pszProtocol = PLCC_DN_TCPIP_L2ROUTE, int bMotorola = 0, int bLoadSymbols = 1, unsigned long ulTimeout = PLCHANDLER_USE_DEFAULT, unsigned long ulPort = 1200); 
    virtual long ConnectRs232ViaGateway(char *pszGatewayIP, short sPort, unsigned long ulBaudrate, int bMotorola = 0, int bLoadSymbols = 1, unsigned long ulTimeout = PLCHANDLER_USE_DEFAULT);
    virtual long ConnectRs232ViaGatewayEx(char *pszGatewayIP, short sPort, unsigned long ulBaudrate, int bMotorola = 0, int bLoadSymbols = 1, unsigned long ulTimeout = PLCHANDLER_USE_DEFAULT, EXT_RS232_PARAMStyp *pExtParams = NULL);
    virtual long ConnectTcpipViaArti(char *pszPlcIP, char *pszProtocol = PLCC_DN_TCPIP_L2ROUTE, int bMotorola = 0, int bLoadSymbols = 1, unsigned long ulTimeout = PLCHANDLER_USE_DEFAULT, unsigned long ulPort = 1200);
    virtual long ConnectRs232ViaArti(short sPort, unsigned long ulBaudrate, int bMotorola = 0, int bLoadSymbols = 1, unsigned long ulTimeout = PLCHANDLER_USE_DEFAULT);
    virtual long ConnectToSimulation(char *pszSdbFile, int bLoadSymbols = 1, unsigned long ulTimeout = PLCHANDLER_USE_DEFAULT);
    virtual long ConnectViaGateway3(char *pszGatewayIP, char *pszAddress, int bLoadSymbols = 1, unsigned long ulTimeout = PLCHANDLER_USE_DEFAULT);
    virtual long ConnectViaGateway3Ex(char *pszGatewayIP, unsigned long ulPort, char *pszAddress, int bLoadSymbols = 1, unsigned long ulTimeout = PLCHANDLER_USE_DEFAULT);
    virtual long ConnectViaArti3(char *pszAddress, int bLoadSymbols = 1, unsigned long ulTimeout = PLCHANDLER_USE_DEFAULT);
    virtual long ConnectToSimulation3(char *pszSdb3XmlFile, int bLoadSymbols = 1, unsigned long ulTimeout = PLCHANDLER_USE_DEFAULT);


    // Attention: The structure of the service must be known in detail! 
    //            An erroneous service might cause a crash of the PLC! 
    // Send own service to plc and receive reply
    virtual long SyncSendService(/*[In]*/ unsigned char *pbySend, /*[In]*/ unsigned long ulSendSize, /*[Out]*/ unsigned char **ppbyRecv, /*[Out]*/ unsigned long *pulRecvSize);
    // Send own service to plc
    virtual long AsyncSendService(/*[Out]*/ int *piInvokeId, /*[In]*/ unsigned char *pbySend, /*[In]*/ unsigned long ulSendSize, /*[In]*/ CPLCHandlerCallback *pAsyncServiceCallback = NULL);
    // Get service reply
    virtual long AsyncGetServiceReply(/*[In]*/ int *piInvokeId, /*[Out]*/ unsigned char **ppbyRecv, /*[Out]*/ unsigned long *pulRecvSize, long *plServiceResult);
    // Get SessionId for Device services (only used for GW3 and ARTI3) 
    virtual unsigned long GetDeviceSessionId(void);
};

So how can I create this object?

I added the line :

pPLCHandler = new CEasyPLCHandler(RTS_INVALID_HANDLE);

and get some unresolved external errors:

[ilink32 Error] Error: Unresolved external 'CEasyPLCHandler::~CEasyPLCHandler()' referenced from C:\USERS\BART\DOCUMENTS\EMBARCADERO\STUDIO\PROJECTS\REALTEST\WIN32\DEBUG\UNIT1.OBJ

But these are already in the other file? Why can't he use these?

Bart
  • 717
  • 1
  • 9
  • 28
  • Why do you declare a pointer? Simply write `static CEasyPLCHandler pPLCHandler;`. Otherwise call `pPLCHandler = new CEasyPLCHandler(/* your args*/);` at the beginning of `main()` – πάντα ῥεῖ Sep 21 '15 at 08:41
  • I need the pointer part, else he will complain about other items. I just noticed I had to add an extra line: `pPLCHandler = new CEasyPLCHandler(RTS_INVALID_HANDLE);`. Sadly I get some new errors now, with unresolved externals – Bart Sep 21 '15 at 08:46

1 Answers1

3

As...the Greek person whose name I can't spell, already correctly said, you're not initializing the pointer. A static or global simple variable (int, double, char and their pointers) will always be initialized to 0, so that's where the NULL comes from.

In order to initialize a static object correctly, you either need to use the pointer and new or use something like static CEasyPLCHandler PLCHandler(RTS_INVALID_HANDLE);, which will construct the object and save you the new as well as the subsequent delete (saving you from a memory leak)

From the looks of it however, you're missing the actual shared library that contains the code for your CEasyPLCHandler object (at least that's what the linker error tells me).

Please remember that, if you decide to go for an automatic static object, that you'll need to access it with . instead of ->.

Refugnic Eternium
  • 4,089
  • 1
  • 15
  • 24
  • Odd thing is, I do have the `new` part and I give him some values, Code: `pPlcHandler = new CEasyPLCHandler(RTS_INVALID_HANDLE);` so it should create the object. It still gives the error : Unresolved external 'CEasyPLCHandler::CeasyPLCHandler(void *) – Bart Sep 21 '15 at 11:43
  • @Bart Yes, oddly enough that's actually an indicator that you're doing it right. When linker errors show up, it means that your code compiled fine, however it has problems with finding the declaration of whatever you pointed it to. In this case, you've supplied it with the header file of CEasyPLCHandler, however you most likely forgot to link to the library. Have you added the .lib to the project? – Refugnic Eternium Sep 21 '15 at 12:46
  • Not yet, I'm trying to do that but I get some issues with that now, since C++ builder isn't happy with my library. giving me the following error: .lib contains invalid OMF record, type 0x21(possibly COFF). You can follow this issue here: http://stackoverflow.com/questions/32695738/linker-error-contains-invalid-omf-record-2 – Bart Sep 21 '15 at 12:52