Link to home
Start Free TrialLog in
Avatar of rustycp
rustycp

asked on

How to add a third party library into my Visual Studio 2013 solution

I am able to open, compile and run the openzwave cpp example app "MinOZW" found at:

https://code.google.com/p/open-zwave/source/browse/#svn%2Ftrunk%2Fcpp%2Fexamples%2Fwindows%2FMinOZW

I am also able to open, compile and run the open source webserver solution found at:

https://github.com/sunsetbrew/civetweb/tree/master/examples/embedded_cpp

However what I'd like to do is add the civetweb embeddable webserver to my openzwave example app solution in VS2014, and add it for use in the openzwave app.

I'm extremely new with VS and not clear how to do this.

Can anybody tell me:

a) the steps to add the civet embedded webserver referenced above to my openzwave example app solution "MinOZW" in VS2013 in the normal way?

b) a few lines of code to add somewhere in my openzwave app "Main.cpp" to see that it is working using the debugger (even if it doesn't really do anything, I can see in the debugger what is happening)

Thank you!
Avatar of sarabande
sarabande
Flag of Luxembourg image

i found some code which might help you.

http://root.cern.ch/root/htmldoc/src/TCivetweb.cxx.html

they used the civet webserver functions as base for their own c++ webserver classes.

from their code, I would think you need to do the following:

put the path to the folders with civetweb.h and civetweb.lib in your VC++ directories, in both the header and library sections of your project properties. this will be under Projects - your_project Properties -  Configuration Properties - VC++ directories. once the path is added, you should be able to #include <civetweb.h> in your code. to link with civetweb.lib add "civetweb.lib" at Projects - your_project Properties -  Configuration Properties - Linker - Input - Additional Dependencies.

Sara
ASKER CERTIFIED SOLUTION
Avatar of Chris Raisin
Chris Raisin
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of rustycp
rustycp

ASKER

Thanks guys, I will try this when I get home (at work right now, this is a hobby project for me).  This sounds like exactly the kind of guidance I needed.  I will report back here on the result.
Avatar of rustycp

ASKER

I did finally get the civetweb added and it will compile.  Mostly it was the paths in the project settings that were difficult to get right. But crasis the process you described got me looking in the right places to get it working.

Now actually adding some code from the civet server example works, but the thread seems to be blocking at the windows "GetMessage()" in the main loop.  My breakpoint stops there and never continues. So I'm guessing that's why it doesn't respond when I hit the http url with a browser, because it's hung up on GetMessage().  It only goes past GetMessage() when I do something in the app window, thus firing an event.  I thought civetserver was supposed to be multithreaded so I don't completely understand why it doesn't still fire it's event to handle the request.

So getting closer, will mess with it later today.

      while (GetMessage(&msg, NULL, 0, 0))
      {
            if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
            {
                  TranslateMessage(&msg);
                  DispatchMessage(&msg);
            }
      }
Avatar of rustycp

ASKER

Ok I fixed the issue of the GetMessage() function blocking by using this way of getting the messages, which times out:

BOOL GetMessageWithTimeout(MSG *msg, UINT to)
{
      BOOL res;
      UINT_PTR timerId = SetTimer(NULL, NULL, 1000, NULL);
      res = GetMessage(msg, NULL, 0, 0);
      KillTimer(NULL, timerId);
      if (!res)
            return FALSE;
      if (msg->message == WM_TIMER && msg->hwnd == NULL && msg->wParam == timerId)
            return FALSE; //TIMEOUT! You could call SetLastError() or something...
      return TRUE;
}


Still not quite working, but I can't help but think I'm getting close.
Avatar of rustycp

ASKER

The issue I'm having now is that when I start the debugger, it goes into the initialize function I created for the webserver, but then the app is not listening on the port, so clearly something is not happening right.  Below is my initialize function, which I call from my main function.  I'm not clear on what this line does:

      CivetServer server(options);

I was thinking that maybe the problem is that the "server" variable is not global, so it's gone as soon as I exit the function?  

void InitializeWebserver()
{

      Log::Write(LogLevel_Always, "Starting http api");

      const char * options[] = { "document_root", DOCUMENT_ROOT,
            "listening_ports", PORT, 0
      };

      CivetServer server(options);

      server.addHandler(EXAMPLE_URI, new ExampleHandler());
      server.addHandler(EXIT_URI, new ExitHandler());
      server.addHandler("/a", new AHandler());
      server.addHandler("/a/b", new ABHandler());
      server.addHandler("**.foo$", new FooHandler());

      //      printf("Browse files at http://localhost:%s/\n", PORT);
      //      printf("Run example at http://localhost:%s%s\n", PORT, EXAMPLE_URI);
      //      printf("Exit at http://localhost:%s%s\n", PORT, EXIT_URI);

      Log::Write(LogLevel_Always, "http api successfully started");

}
Avatar of rustycp

ASKER

That is indeed the problem, when I put this at the end of that function:

      while (!exitNow) {
            Sleep(1000);
      }


the web server runs correctly.

So I am thinking the "server" var needs to be global so it's not lost when I leave the function. But I'm not sure how to do that.  Probably if I understand what this line does then I'll have a better idea:

      CivetServer server(options);
but the thread seems to be blocking at the windows "GetMessage()" in the main loop.  

I hope the message loop is in your main thread and not in a worker thread. you may not process dialog messages in  a worker thread. the GetMessage is not thread-safe and by calling TranslateMessage and DispatchMessage you are calling functions of the main thread (the dialog thread) asynchronously from thread. moreover, you were removing and handling all the messages what makes the main thread freezing as it has no messages to perform. if the thread has its own (pseudo) window, you may process the messages of this window only. but that doesn't seem the case here.

if you got data in a thread and want to send them to the main dialog, you need to send them by calling PostMessage(yourMainHwnd, yourMessageId, (WPARAM)yourThreadId, (LPARAM)ptrToData)  which is thread-safe.

in your main thread you would catch the message by providing an appropriate event handler. this handler now is synchronous with the main thread and you can safely process the messages.

if you post your code here (please use code tags) we could check whether your design is thread-safe.

Sara
I can't help you there since I am not a "C" programmer and I have not actually dealt with web servers etc.

Sorry...but your original question related only to making two projects "co-habit a solution" and hopefully that has been covered.

These extra questions regarding the coding should be submitted as a seperate question for consideration by C/C++/C#  experts.

Cheers  
Chris   :-)
I was thinking that maybe the problem is that the "server" variable is not global,
instead of a global server, you may use a little helper class which provides the server as a singleton.

//css.h  civet server singleton

#ifndef CSS_H
#define CSS_H

#include <civetserver.h>

class CSS
{
      // private constructor prevents creating an instance
      CSS() {}
public:
      static CivitServer & GetInstance() 
      {
            static CivitServer theServer;
            return theServer;
      }
};

Open in new window

#endif

using that class you can access the server singleton from everywhere by code like

CivetServer & server = CSS::GetInstance();

Open in new window


Sara
note, even if the civetweb is multi-threaded it doesn't mean that you could access shared data without protection from multiple threads.

instead you may use a critical section instance to make all access to shared data or shared objects exclusively.

Sara
Avatar of rustycp

ASKER

Both in the class example and if I just use code to declare a global variable, I get the error "No suitable constructor exists for CivetServer."

So for example if I change this code:

      CivetServer server(options);

to this:

        CivetServer server = new CivetServer(options);

I get the error "No suitable constructor exists for CivetServer"

What does that syntax do exactly? I've having a hard time googling for it because I don't know what it's called.
Avatar of rustycp

ASKER

ok gonna start a new question thread per the suggestion, thank you
 I get the error "No suitable constructor exists for CivetServer."

Open in new window

the error means, that CivetServer hasn't a default constructor (taking no argument).

I see in your code that you pass an argument 'options' when you construct the CivetServer instance.

that also must be done in the CSS::GetInstance function:

class CSS
{
      ...     
      static CivitServer & GetInstance() 
      {
           const char * options[] = { "document_root", DOCUMENT_ROOT,
             "listening_ports", PORT, 0   };

            static CivitServer theServer(options);
            return theServer;
      }

Open in new window

when the function was called it returns a reference (not a pointer) to the static CivetServer object of the GetInstance function. the object was constructed with the first call and keeps alive until your program ends. it can be called from different threads without problems. Because the function is static, it always would return a reference to one and only singleton instance of CivetServer (as long as you don't use the class in different executables (.exe or .dll)

CivetServer server = new CivetServer(options);

Open in new window

in c++ the operator 'new' returns a pointer. hence the above statement doesn't compile because it translates to

CivetServer server(pointer_to_CivitServer);

Open in new window


what is wrong, cause the constructor of CivetServer takes an array of const char pointers like the 'options' array.

the following code would compile:

CivetServer * server = new CivetServer(options);

Open in new window

however, you would need to share the pointer variable 'server' between your functions and your threads (for example by making it a global variable).

generally, you should avoid to using global variables as their usage is much more error-prone. global pointers are worse because you will have troubles to free the allocation at end of program as there is no instance which is responsible for this.

Sara