🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.cppbuilder.internet.socket
7 messages
7 total messages Started by Mark Jacobs Tue, 06 Jun 2006 10:36
BDS2006 requires WSAStartup be called...
#2285
Author: Mark Jacobs
Date: Tue, 06 Jun 2006 10:36
73 lines
3294 bytes
The following works correctly under BCB5. Virgin BCB2006 VCL project, drop a 
button onto the form :-

//--HEADER FILE------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <WSockets.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
   TButton *Button1;
   void __fastcall Button1Click(TObject *Sender);
private: // User declarations
public:  // User declarations
   __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

//--SOURCE FILE------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
 : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  struct hostent *mhstj; struct in_addr mjinad;
  unsigned long eha; int ii=0; AnsiString cret;
  mhstj=gethostbyname("");
  if (!mhstj)
  {
    ShowMessage("Socket Error "+AnsiString(WSAGetLastError()));
    return;
  }
  cret=AnsiString(mhstj->h_name);
  while (mhstj->h_addr_list[ii])
  {
    memcpy(&mjinad,mhstj->h_addr_list[ii++],sizeof(in_addr));
    cret+="\n"+AnsiString(inet_ntoa(mjinad));
  }
  ShowMessage("Hello  - Your IP Details are :-\n"+cret);
}
//---------------------------------------------------------------------------

In BCB5 I get the IP details as expected. In BDS2006 error 10093 is returned 
implying something about WSAStartup not being called. Having looked at the 
structure required to set up a call to WSAStartup, I am not happy. Why doesn't 
this work as is?
-- 
�
Mark Jacobs
DK Computing
http://www.dkcomputing.co.uk
Re: BDS2006 requires WSAStartup be called...
#2286
Author: Remy Lebeau (TeamB)
Date: Tue, 06 Jun 2006 16:42
71 lines
3336 bytes
"Mark Jacobs" <http://www.jacobsm.com/mjmsg?Borland%20Newsgroup> wrote in
message news:44855a92$1@newsgroups.borland.com...

>   mhstj=gethostbyname("");

To get the local IP, you should be using gethostname() instead of
gethostbyname("").

>     memcpy(&mjinad,mhstj->h_addr_list[ii++],sizeof(in_addr));
>     cret+="\n"+AnsiString(inet_ntoa(mjinad));

You don't need to copy the address before converting it.  You can convert
the original value directly:

    cret += "\n" + AnsiString(inet_ntoa(* (in_addr*)
mhstj->h_addr_list[ii++]);

> In BCB5 I get the IP details as expected. In BDS2006 error
> 10093 is returned implying something about WSAStartup not
> being called.

As well it should be.  You have to call WSAStartup() before calling any
other socket-related functions.  You should be doing that in any version of
BCB.  If BCB 5 is not requiring you to do that, then you likely have a
package installed that is calling WSAStartup() automatically during its
initialization.  You should not be relying on that behavior in your own
code.  Always explitically call WSAStartup() and WSACleanup() in any socket
code that you write yourself.

> Having looked at the structure required to set up a call to WSAStartup, I
am not happy.

You don't need to set up anything in order to call WSAStartup().  It only
has 1 input parameter, the requested version.  The WSADATA structure is an
output parameter so that you know which version is actually being used,
which may be different than the version you request.  You can ignore the
structure if you are only going to be using socket operations that are
supposed all the way back to v1.0, ie:

    bool WasInitialized = false;

    __fastcall TForm1::TForm1(TComponent *Owner)
        : TForm()
    {
        // can't use WSAGetLastError() with WSAStartup()...
        WSADATA wsa = {0};
        int ret = WSAStartup(MAKEWORD(1, 0), &wsa);
        WasInitialized = ( ret != 0 );
        if( !WasInitialized )
            MessageBox(NULL, ("Startup Error " + AnsiString(ret)).c_str(),
"Error", MB_OK | MB_ICONERROR);
    }

    __fastcall TForm1::~TForm1()
    {
        if( WasInitialized )
            WSACleanup();
    }

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        //...
    }

> Why doesn't this work as is?

Because it is not supposed to in the first place.


Gambit
Re: BDS2006 requires WSAStartup be called...
#2287
Author: Michel Leunen
Date: Tue, 06 Jun 2006 17:54
17 lines
1616 bytes
Mark Jacobs wrote:

> #include <WSockets.hpp>

Besides what Remy told you, this isn't the right header to include if 
you want to use sockets. #include <winsock.h> or <winsock2.h> instead. 
If I'm not mistaken, WSockets.hpp comes from the ICS components suite 
and you are not using one of these components in your sample.

Michel
-- 
----------------------------------------
Michel Leunen
mailto: see my homepage.
C++Builder, BCC5.5.1 Web site:
http://www.leunen.com/
----------------------------------------
Re: BDS2006 requires WSAStartup be called...
#2289
Author: Remy Lebeau (TeamB)
Date: Tue, 06 Jun 2006 18:12
20 lines
1623 bytes
"Michel Leunen" <nospam@noreply.please> wrote in message
news:4485c157$1@newsgroups.borland.com...

> > #include <WSockets.hpp>

I didn't even catch that.  In that case, my earlier statement:

    "If BCB 5 is not requiring you to do that, then you *LIKELY* have a
package installed that is calling WSAStartup() automatically during its
initialization."

Should be changed to this instead:

    "If BCB 5 is not requiring you to do that, then you *DEFINATELY* have a
[third-party] package [included in the project] that is calling WSAStartup()
automatically during its initialization."


Gambit
Re: BDS2006 requires WSAStartup be called...
#2292
Author: Mark Jacobs
Date: Wed, 07 Jun 2006 08:49
14 lines
1468 bytes
Remy Lebeau (TeamB) wrote:
> You have to call WSAStartup() before calling
> any other socket-related functions.

What other functions would I have to use in order to require WSAStartup? What 
3rd party VCL components use windows sockets? If there is a 3rd party library 
calling WSAStartup automatically, how can I identify which one it is? If 
WSAStartup has been called multiple times, how do oyu know how many times to 
call WSACleanup?
-- 
�
Mark Jacobs
DK Computing
http://www.dkcomputing.co.uk
Re: BDS2006 requires WSAStartup be called...
#2295
Author: Remy Lebeau (TeamB)
Date: Wed, 07 Jun 2006 17:37
49 lines
3398 bytes
"Mark Jacobs" <http://www.jacobsm.com/mjmsg?Borland%20Newsgroup> wrote in
message news:4486930a@newsgroups.borland.com...

> What other functions would I have to use in order to require WSAStartup?

All of the socket-related functions require WSAStartup().  It initializes
the calling thread to use the socket library.  For example, one thing it
does is to create the TLS slot (thread local storage) that WSAGetLastError()
uses to store error codes.  That is why WSAGetLastError() can't be used
until after WSAStartup() returns a successful return value.  If WSAStartup()
fails, there is no guarantee that the TLS has been created.

> What 3rd party VCL components use windows sockets?

There are too many to list.  There are large libraries, such as Indy, ICS,
and Synapse.  But there are numerous other component implementations that
use sockets for other, more specialized, purposes.  That is like asking
"what third-party components use TWinControl".

> If there is a 3rd party library calling WSAStartup automatically

We've already covered that.  The code you showed earlier is including an ICS
header file.  So ICS is the one calling WSAStartup() for its own purposes.

> how can I identify which one it is?

There is no straight-forward way to do that.  Nor should you try to care
about it.  As I already told you earlier, just call WSAStartup() in your own
code regardless of what the rest of the project is doing.  It is perfectly
safe to call WSAStartup() multiple times.  Like any other API, WinSock is
implemented as a DLL.  Calling WSAStartup() multiple times will only load
the DLL once the first time, and then increment its reference count on
subsequent calls.  Just make sure that you call WSACleanup() once for each
successful WSAStartup() so that the reference count is balanced, otherwise
the DLL will not be unloaded properly.

> If WSAStartup has been called multiple times, how do oyu
> know how many times to call WSACleanup?

You have to call WSACleanup() once, and only once, for each successful call
to WSAStartup() that you make.  If you call WSAStartup() in your own code
once, and it succeeds, then call WSACleanup() only once in your own code.
Every other library/component that also calls WSAStartup() will be doing the
same thing.  You DO NOT call WSACleanup() in your own code for other
people's calls to WSAStartup().


Gambit
Re: BDS2006 requires WSAStartup be called...
#2296
Author: Mark Jacobs
Date: Thu, 08 Jun 2006 10:24
10 lines
1320 bytes
Remy Lebeau (TeamB) wrote:
...

Thanks a lot for your thorough explanations - I am now rewriting my code to be 
WSAStartup compliant. Thanks again,
-- 
�
Mark Jacobs
DK Computing
http://www.dkcomputing.co.uk
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads