Problem bei C/C++ Win32-Projekt

xKorbix

Grünschnabel
Hallo,

wo ich mein Problem habe, ist ja schon dem Titel zu entnehmen. Jezt noch etwas genauer.
Code:
   Application::EnableVisualStyles();
   Application::SetCompatibleTextRenderingDefault(false); 
   Form1 ^ f1 = gcnew Form1();
   ........  ........ ........
   HANDLE hThread = CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE)&ThreadProc, 0, 0, NULL);
   Application::Run(f1);

hier estmal groß der Anfang und das Ende meiner main-Funktion. Zusätzlich habe ich noch eine Form (Form1) in der ich jetzt TextBoxen und Buttons habe. Funktioniert alles einwandfrei. Wie man im Codeausschnitt sieht, möchte ich aber noch einen Thread im Hintergrund laufen lassen und ab jetzt fängt mein Problem an.
Bei der Win32-Konsolenanwendung hat das mit dem Thread super funktioniert. Doch jetzt bei meinem Win32-Projekt fliegt er beim "CreateThread" raus. Ohne Fehlermeldung wohlgemerkt. In der Ausgabe steht lediglich "...wurde mit Code -1073741819 (0xc0000005) beendet". Also nicht normal beendet.
Kann mir einer von euch dabei helfen?
 
Hi.

Verwende den Debugger.

Schalte First-chance-Exceptions ein.

0xc0000005 ist AccessViolation - du greifst auf fremde Speicherbereiche zu.

Warum verwendest du nicht die Klassen im System.Threading Namensraum wenn du .NET verwendest?

Und gibt es einen Grund C++/CLI zu verwenden, anstatt z.B. C#?
 
Danke für die schnelle Antwort.
C# habe ich noch nie verwendet, darum dachte ich ich nehme C++, da ich das in meiner Arbeit verwende. Das Programm wollte ich auch nur mal kurz machen, um udp-pakete zu senden und zu empfangen. Hat in der Konsole ja super funktioniert, aber wenn ein udp-paket reingekommen ist, während ich den Inhalt für das zu sendende udp-paket eingetippt hab, hat sich das alles so komisch überschrieben. Mit der Threadsache habe ich mich leider auch nicht so sehr beschäftigt. Habe ein wenig gegoogelt, ein paar möglichkeiten gesucht und mir hat diese am besten gefallen. System.Threading habe ich garnicht gesehen gehabt. Ist das besser? Dann würde ich das auch einmal ausprobieren.

EDIT: // habe auch gerade einmal den Tipp mit first-chance-Exceptions ausprobiert. Sprich habe im Debugger System.ApplicationException aktiviert. Aber er schmeißt mir trotzdem keine Exception bzgl. meines Fehlers.
 
Zuletzt bearbeitet:
System.Threading habe ich garnicht gesehen gehabt. Ist das besser?
Es ist einfacher - wobei das etwas davon abhängt was ThreadProc bei dir ist bzw. macht.

Nebenbei, stinkt der Cast bei ThreadProc ziemlich zum Himmel. Also zeig deinen Code.
EDIT: // habe auch gerade einmal den Tipp mit first-chance-Exceptions ausprobiert. Sprich habe im Debugger System.ApplicationException aktiviert. Aber er schmeißt mir trotzdem keine Exception bzgl. meines Fehlers.
Wie gesagt 0xc0000005 ist eine AccessViolation. Du müßtest also bei Debug -> Exceptions -> Win32 Exceptions -> 0xc0000005 aktivieren...
 
Hallo xKorbix,

"CreateThread" sollte nicht das Problem sein, sondern das, was du in "ThreadProc" tust. Zeige doch mal deine Thread-Funktion bzw. nimm mal probeweise alle Funktionalität raus.

Gruß
MCoder
 
Alles Klar das Problem mit dem Thread ist gelöst. Habe gerade mal System.Thrading verwendet. Jetzt wenn ich hier schon mit meinem Threading-Problem im Gespräch bin, könntet ihr mir noch schnell eine letzte Frage bzgl. meines Projekts beantworten. Anbei füge ich mal meinen kompletten Code ein. Mein Problem dabei ist, dass ich den Thread mit Parametern starten möchte.
Bitte nicht vom "wirrwarr" abschrecken, das wird noch angepasst. Ich habe jetzt erstmal versucht, so schnell wie möglich von meiner Konsolenanwendung auf ein Win32-Projekt umschreien.

Und hier noch der Fehler, wenn ich den Thread mit Parametern starte.
error C3352: 'void ThreadExample::ThreadProc(FormDes::Form1 ^)' : the specified function does not match the delegate type 'void (System::Object ^)'

Code:
// FormDes.cpp: Hauptprojektdatei.
#include "stdafx.h"
#include "Form1.h"
#include <winsock2.h>
#include <string>
using namespace std;
using namespace FormDes;
using namespace System;
using namespace System::Threading;
SOCKET udpsock;
SOCKADDR_IN remoteAddr;
SOCKADDR_IN addr;
int addrLen;
public ref class ThreadExample
{
public:
   // The ThreadProc method is called when the thread starts.
   static void ThreadProc(Form1^ f1)
   {
      char* mystr = new char[255];
      string str = "incomming";
      long ret;
      while(1) {
      ret = recvfrom(udpsock, mystr, 255, 0, (SOCKADDR*)&remoteAddr, &addrLen);
      mystr[ret] = '\0';
      string strdp = ":";
      string addr = static_cast<string>(inet_ntoa(remoteAddr.sin_addr));
      //strcat(str,inet_ntoa(remoteAddr.sin_addr));
      //strcat(str,strdp);
      //strcat(str,ntohs(remoteAddr.sin_port));
      //strcat(str,mystr);
      String^ str2 = gcnew String(str.c_str());
      f1->setText1(str2);
    }
   }

};
char* test();
char* test(){
  char hostname[255];
  char *szIPAddress;
  WORD wVer;
  WSADATA wData;
  PHOSTENT hostinfo;
  wVer = MAKEWORD( 2, 0 );
  if ( WSAStartup( wVer, &wData ) == 0 )
  {
    if( gethostname ( hostname, sizeof(hostname)) == 0)
    {
       if((hostinfo = gethostbyname(hostname)) != NULL)
       {
        szIPAddress = inet_ntoa (*(struct in_addr *)*hostinfo->h_addr_list);
       }
    }
  WSACleanup();
  }
  return szIPAddress;
}

//Main function which starts out each thread
int main(array<System::String ^> ^args)
{
	// Aktivieren visueller Effekte von Windows XP, bevor Steuerelemente erstellt werden
	Application::EnableVisualStyles();
	Application::SetCompatibleTextRenderingDefault(false); 
  Form1^ f1 = gcnew Form1(); 
  long ret;
  string mystr;
  short portnum = 7001;
  short sendPort= 7002;
  string address = "127.0.0.1";
  WSADATA wsa;
  ret = WSAStartup (MAKEWORD (1,1), &wsa);

  udpsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

  addrLen = sizeof(SOCKADDR_IN);

  //----------------------------------
  SOCKADDR_IN iaddr;
  iaddr.sin_family      = AF_INET;
  iaddr.sin_port        = htons(sendPort);
  iaddr.sin_addr.s_addr = ADDR_ANY;
  //----------------------------------

  addr.sin_family      = AF_INET;
  addr.sin_port        = htons(portnum);
  addr.sin_addr.s_addr = inet_addr(address.c_str());

  ret = bind(udpsock, (SOCKADDR*)&iaddr, addrLen);
  string szIPAddress = test();
  String^ str2 = gcnew String(szIPAddress.c_str());
  str2 = str2 + ": connected";
  f1->setText1(str2);

  int errcode = WSAGetLastError();
  if (ret != 0) {
    String^ infoStr = "Error bind to port " + portnum + " -> errcode = " + errcode;
    f1->setInfo(infoStr);
  }
  else
  {
    String^ infoStr = "Bind on port " + portnum + ".";
    f1->setInfo(infoStr);
    mystr = "connected";
    ret = sendto(udpsock, mystr.c_str(), (int)strlen(mystr.c_str()), 0, (SOCKADDR*)&addr, addrLen);
  }
  Thread^ newThread = gcnew Thread(gcnew ParameterizedThreadStart(&ThreadExample::ThreadProc));
  newThread->Start(f1);
        //Thread^ oThread = gcnew Thread( gcnew ParameterizedThreadStart( &ThreadExample::ThreadProc ) );
        //oThread->Start();
   //CreateThread(NULL, 0,(LPTHREAD_START_ROUTINE)&ThreadProc, 0, 0,&dwThreadId);
   Application::Run(f1);

Danke im Vorraus
 
Hallo,

bitte mal ab und zu in die MSDN schauen. Die Signatur der Thread-Methode muss muss so ausschauen (steht übrigens auch in der Fehlermeldung):
C++:
static void ThreadProc(Object^ f1)
{

}
Da die Form von Objekt abgeleitet ist, kannst du sie trotzdem einfach übergeben und must dann nur casten.

BTW: Wenn du schon mit .NET arbeitest, solltest du das auch konsequent durchziehen und auch die Socket-Klassen des Frameworks benutzen. Bei Gleichzeitiger Verwendung von Managed und Unmanaged Code gibt es spätestens dann Probleme oder zusätzlichen Aurwand, wenn du die Daten zusammenbringen willst.

Gruß
MCoder
 
Zuletzt bearbeitet:
Das wird so nicht funktionieren, da man nicht einfach von einem anderen Thread auf Komponenten einer Form zugreifen darf.

Grundsätzlich kann man bei der Thread.Start Methode einen Parameter übergeben.

Für deine Zwecke (ein Thread im Hintergrund einer Form auszuführen) ist der System.ComponentModel.BackgroundWorker besser geeignet. :google:

Alternativ wäre low-Level die Verwendung von ControlBeginInvoke möglich. Siehe auch http://msdn.microsoft.com/en-us/library/757y83z4.aspx
 
Zuletzt bearbeitet:
Danke für eure Hilfe ihr habt mir viel geholfen. Jetzt funktioniert erstmal alles. Jetzt werd ich demnächst mal mehr ins Detail gehen und mal auf eure Tipps eingehen. Das mit dem zugreifen auf eine Komponente einer Form hab ich schon mit folgedem gelöst
Code:
SetTextDelegate^ d = gcnew SetTextDelegate(this, &Form1::setText1);
this->Invoke(d, gcnew array<Object^> { add_str });
Vorallem werde ich auf den Tipp eingehen, gleich alles mit .Net zu machen.
Oder ich machs gleich mit C#. Wollte das sowieso schon lange mal lernen.
Also vielen vielen Dank für eure Hilfe.

Gruß

Korbi
 

Neue Beiträge

Zurück