Solved

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

Posted on 2014-10-12
14
682 Views
Last Modified: 2014-10-14
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!
0
Comment
Question by:rustycp
  • 7
  • 5
  • 2
14 Comments
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
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
0
 
LVL 13

Accepted Solution

by:
Chris Raisin earned 500 total points
Comment Utility
You simply Click on project and select "Add Project".

You will end up with two projects in the same solution.

Make sure you mark the project which you want to "kick off" when the program starts as the "StartUp Project" by right clicking the project name in your Solution Explorer, then selecting "Set as Startup project" (be careful though, once the project becomes the startup project then the menu will say "Set Startup Projects..." which is a different thing ( a menu for manipulating Projects).
(This is what you do when you incorporate InstallSheild as your disbursement package).

Basically you can have lots of programs in one disbursement, one calling another if you wish).

Doing this will pull in all the required code from the extra project. You will just have to make sure you have all required external libraries ("Imports") required by the second Project referenced in its setup.

When you "Build your solution both projects will compile. When you "Publish" a sinclge setuup will be created but when it is run, both Projects will install. Using "Shell" calls in one application, you can open asecond application if you wish. I have never tried "sharing" code bwteen applications but I suppose it is possibleprovided it is in a DLL. I do not think thereis a way you can "reference" the second project from the first though and both application run a seperate self-contained entities. (But don't quote meon that.I just have not tried it!)

Cheers
Chris (Melbourne - Australia)
0
 
LVL 2

Author Comment

by:rustycp
Comment Utility
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.
0
 
LVL 2

Author Comment

by:rustycp
Comment Utility
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);
            }
      }
0
 
LVL 2

Author Comment

by:rustycp
Comment Utility
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.
0
 
LVL 2

Author Comment

by:rustycp
Comment Utility
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");

}
0
 
LVL 2

Author Comment

by:rustycp
Comment Utility
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);
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 32

Expert Comment

by:sarabande
Comment Utility
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
0
 
LVL 13

Expert Comment

by:Chris Raisin
Comment Utility
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   :-)
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
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
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
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
0
 
LVL 2

Author Comment

by:rustycp
Comment Utility
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.
0
 
LVL 2

Author Comment

by:rustycp
Comment Utility
ok gonna start a new question thread per the suggestion, thank you
0
 
LVL 32

Expert Comment

by:sarabande
Comment Utility
 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
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
A theme is a collection of property settings that allow you to define the look of pages and controls, and then apply the look consistently across pages in an application. Themes can be made up of a set of elements: skins, style sheets, images, and o…
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now