tags:

views:

124

answers:

4

Hello there,

I'm now creating a file transaction system (through FTP) using wxWidgets for the GUI and a multithreading class from CodeProject (http://www.codeproject.com/KB/threads/SynchronizedThreadNoMfc.aspx) - Please read the article first for reference.

In my GUI, I have a textbox (wxTextCtrl) that stores the file path that wanted to be sent to the FTP server, and I wanted to get its value through the multi-threading function.

Here is my code so far: (simplified; multiple files)

/////// Organizer.h // Main header file that utilizes all other headers
#include <wx/wx.h>
#include <wx/datectrl.h>
#include <wininet.h>
#pragma comment(lib, "wininet.lib")
#include "Threading.h"
#include "MainDlg.h"
#include "svDialog.h"

///////// Threading.h // Please read the article given above
#include "ou_thread.h"
using namespace openutils;

extern HINTERNET hInternet; // both declared in MainDlg.cpp
extern HINTERNET hFtpSession;

class svThread : public Thread
{
private:
  char* ThreadName;
public:
  svThread(const char* szThreadName)
  {
    Thread::setName(szThreadName);
    this->ThreadName = (char* )szThreadName;
  }
  void run()
  {
    if(this->ThreadName == "Upload")
    {
    hInternet = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
    hFtpSession = InternetConnect(hInternet, L"myserver.com", INTERNET_DEFAULT_FTP_PORT, L"user", L"pass", INTERNET_SERVICE_FTP, 0, 0);

    std::string filenameOnServer((char* )tb_file->GetValue().c_str()); // HERE..the tb_file..
    std::vector<std::string> filepathParts;
    __strexp(filenameOnServer, "\\", filepathParts); // this is user-defined function that will split a string (1st param) with the given delimiter (2nd param) to a vector (3rd param)
    filenameOnServer = filepathParts.at(filepathParts.size() - 1); // get only the filename

    if(FtpPutFile(hFtpSession, tb_file->GetValue().c_str(), (LPCWSTR)filenameOnServer.c_str(), FTP_TRANSFER_TYPE_BINARY, 0))
    {
     MessageBox(NULL, L"Upload Complete", L"OK", 0);
    }
    else
    {
     MessageBox(NULL, L"Upload Failed", L"OK", 0);
    }
    }
  }
};

////////// svDialog.h
class svDialog : public wxFrame
{
public:
  svDialog(const wxString &title);
  void InitializeComponent();
  void ProcessUpload(wxCommandEvent &event); // function (button event) that will start the UPLOAD THREAD
  wxTextCtrl *tb_file; // this is the textbox
  //....other codes
};

///////////svDialog.cpp
#include "Organizer.h"
Thread *UploadRoutine;

svDialog::svDialog(const wxString &title) : wxFrame(...) // case unrelated
{
  InitializeComponent();
}
void svDialog::InitializeComponent()
{
  tb_file = new wxTextCtrl(...);
  //......other codes
}
void svDialog::ProcessUpload(wxCommandEvent &event)
{
  UploadRoutine = new svThread("Upload");
  UploadRoutine->start();
  //......other codes
}

////// MainDlg.cpp // (MainDlg.h only contains the MainDlg class declaration and member function prototypes)
#include "Organizer.h"

HINTERNET hInternet;
HINTERNET hFtpSession;
IMPLEMENT_APP(MainDlg) // wxWidgets macro

bool MainDlg::OnInit() // wxWidgets window initialization function
{
  //......other codes
}

Well, as you can see in my code above, I wanted to get the content of tb_file (with tb_file->GetValue()) and pass it to the multi-threading function (void run()) for to be uploaded later.

Any kind of help would be appreciated!

Thanks. (and sorry for the long code..)

A: 

Any data that you want run to see can be stored as member data of svThread class. A good way to get it stored as member data would be to pass it as a parameter to the svThread constructor.

ChrisW
+1  A: 

You should store the data the thread needs as member variables of the thread, e.g.:

class svThread : public Thread
{
private:
    const std::string filename_;
public:
    svThread(const std::string& filename)
      : filename_(filename) 
    {}
    void run()
    {
        // ...
            __strexp(filename_, /* ... */);
        // ...
    }
};

void svDialog::ProcessUpload(wxCommandEvent &event)
{
    UploadRoutine = new svThread(tb_file->GetValue());
    // ...
}
Georg Fritzsche
+3  A: 

It's quite simple.

You should create a start function that takes a std::string (or any other parameters) and store it (them) in the svThread object. Then you can access it in the run function:

class svThread : public Thread
{
   private:
      char* ThreadName;
      std::string FileName;

   public:
      svThread(const char* szThreadName)
      {
         Thread::setName(szThreadName);
         this->ThreadName = (char* )szThreadName;
      }

      void Start(const std::string& filename)
      {
         this->FileName = filename;
         Thread::Start();
      }

      void Run()
      {
         // ...
         if(FtpPutFile(hFtpSession, FileName,(LPCWSTR)filenameOnServer.c_str(), FTP_TRANSFER_TYPE_BINARY, 0))
         // ...
      }
};

In your dialog class you just need to start your thread like this:

UploadRoutine = new svThread("Upload");
UploadRoutine->start(tb_file->GetValue().c_str());
Patrice Bernassola
A: 

I'd also make hInternet and hFTPSession not global and pass them to each thread. That way you wont get into trouble later when utilizing multiple ftp sessions for instance. I'd also rather not declare them in maindlg.cpp, the main dialog is a gui part, and those variables do not have any much to do with the gui.

btw what is the purpose of

if(this->ThreadName == "Upload")

I mean, if the thread is meant for uploading, why should it doublecheck that against it's name string?

stijn
I said it is SIMPLIFIED. I didn't add any other unrelated codes.
djzmo