1

I'm a Java programmer forced to do some C++. What a nightmare! I'm trying to send a POST request to a web service like this:

#include <Windows.h>
#include <tchar.h>
#include <WinInet.h>

    static TCHAR hdrs[] = _T("Content-Type: application/x-www-form-urlencoded");
    static TCHAR frmdata[] = _T("id=01&message=test_message");
    static LPCSTR accept[2] = { "*/*", NULL };
    static LPCWSTR tag = L"MyAgent";
    static LPCWSTR requestType = L"POST";

// for clarity, error-checking has been removed
HINTERNET hSession = InternetOpen(tag, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnect = InternetConnect(hSession, _T("desktop-60nl2pl:9998"), INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = HttpOpenRequest(hConnect, requestType, _T("/GUser/login"), NULL, NULL, (LPCWSTR*)accept, 0, 1);
HttpSendRequest(hRequest, hdrs, strlen((char*)hdrs), frmdata, strlen((char*)frmdata));

That code is based on this posting: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/dc74e7bf-3ac9-41a0-b1c7-ece14a76a906/send-post-request-to-simple-php-page-using-wininet?forum=vcgeneral

It compiles but doesn't link. Getting a bunch of these "unresolved external symbol _imp_InternetOpenW referenced in function "class std::vector

Sorry if this is a newby question but I'm not able to understand all the gobbldygook I read about linker errors. Can someone explain in simple terms?

user3217883
  • 1,216
  • 4
  • 38
  • 65
  • 1
    Possible duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – Ken White Mar 15 '18 at 01:05
  • 1
    The only proven way to learn C++ is with a good book. Throwing together random bits of C++ code, pulled off random web sites, without a full understand of what they do, will result in a typical outcome such as this one. It's understandable that you're "forced to do some C++", for some unclear reason. Still, the basic fact is that C++ is the most complicated general programming language in use today, and learning it by trial and error is unlikely to work. You need to start from the beginning, C++ basics, and maybe after a few years you'll know C++ well enough to try network programming. – Sam Varshavchik Mar 15 '18 at 01:13
  • Read the MSDN documentation for the functions you are using. Usually, it says on the page which library you need to link. – M.M Mar 15 '18 at 01:39
  • `strlen((char*)hdrs` -- Do not do this. Never cast strings like this, unless you know what you're doing. The `hdrs` is an array of `TCHAR`, **not** a `char` array. What compiler error do you get if you removed the cast? Whatever that error is, **read it carefully**. The compiler is telling you that the string types are different, and all you did by casting is "shut the compiler up". A `TCHAR` may or may not be a 2-byte character type depending on your compiler options, and a `char` is a single byte character. Casting does **not** convert a two byte char array to a 1-byte char array. – PaulMcKenzie Mar 15 '18 at 02:00
  • Also, to resolve the issue I brought up, use the proper string types and/or string functions that match the string types you're using. In other words, get that code to compile *without casting*. I'm saving you the headache of when you finally do get that code to compile and link, you don't crash due to improper string usage. I also agree with SamV. You can't put together a C++ program "by force". It just doesn't work that way -- your boss or company needs to realize that a bonafide C++ programmer is required to write these types of apps. – PaulMcKenzie Mar 15 '18 at 02:06
  • Paul - I took away the casting and get "argument of type "LPCSTR *" is incompatible with parameter of type "LPCWSTR *" . Note the original code does not use any "LPCWSTR" so not sure why it is complaining yet. Also don't underestimate my abilities. I've been programming 35 years and have overcome much bigger hurdles. I'll get there in a few weeks, not years. Thanks for the input. – user3217883 Mar 15 '18 at 14:50
  • I fixed that problem by adding this: static LPCWSTR filter = L"*/*"; static LPCWSTR accept[2] = { filter, NULL }; But still having issues with hdrs and frmdata. They both say "argument of type "TCHAR *" is incompatible with parameter of type "const char *". If I change the def to static const char* frmdata[] = _T("id=01&message=test_message"); then error under _T says ""initialization with '{...}' expected for aggregate object" – user3217883 Mar 15 '18 at 16:07
  • stack overflow post removed the asterisk after "static const char" – user3217883 Mar 15 '18 at 16:22

2 Answers2

2

You are referencing functions such as InternetOpen, but they are not defined in your code. The live in Win32 libraries that must be linked against your code. In this case, all the InternetXXXX functions live in the WinInet.lib static library and WinInet.dll dynamic link library. You must link against WinINet.lib for your program to compile.

programmerj
  • 1,634
  • 18
  • 29
  • Thank you programmerj. I found WinInet.dll in C:\Windows\SysWOW64 and added that to the Project>Properties>Configuration Properties>Linker>General>Additional Library Directories, per @dgnuff directions. I've removed the casting per PaulMcKenzie suggestion so now I have to overcome other errors. When I get this to work, I will come back and accept one of these answers. – user3217883 Mar 15 '18 at 15:36
  • Also found WinInet.lib and WinInet.h so will add those as well. – user3217883 Mar 15 '18 at 15:42
  • 1
    Going from memory here...but you should probably link against the static library (wininet.lib). Note you can dynamically load the wininet.dll and access functions via the LoadLibrary and GetProcAddress functions, but you would be living on the edge... – programmerj Mar 15 '18 at 15:43
1

TL;DR you're missing a library in your linker options.

Going from .cpp to .exe is a two step operation. Step one is compilation that converts .cpp to .obj. Step two is linking that converts .obj to .exe.

The reason to do this in two steps becomes very apparent when your program becomes big enough to require two or more .cpp files. You compile each .cpp on its own, and then link the two .objs together. That cuts your iteration time dramatically, especially when you have 100 or so .cpp files and have only changed one of them.

During the link phase, the linker also includes various libraries. Most of the really common ones are included automatically so everything just "works right"™ a reasonable percentage of the time. However less commonly used ones, e.g. networking libraries are not included by default and need to be explicitly named in the linker options.

Luckily, Microsoft make it pretty easy to track them down. Take one of the undefined function names, "undecorate" it to get the original back, e.g. InternetOpen and then google for InternetOpen msdn. The first link will take you here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa385096(v=vs.85).aspx and if you scroll right to the bottom, there's a Requirements section. Listed in there is the library you want: wininet.lib so all you have to do is explicitly name it in the Additinal Dependencies field of the Input page of the Linker options under Project Properties, and you should be good to go.

You are using Visual Studio for this, right?

dgnuff
  • 3,195
  • 2
  • 18
  • 32
  • Thank you dgnuff! I added C:\Windows\SysWOW64 folder to Project>Properties>Configuration Properties>Linker>Input>Additional Library Directories and the error went away. – user3217883 Mar 15 '18 at 16:54