Alexander bin ich: C++: Modem ansprechen - klappt nicht

Juten Abend,

ich schlage mich schon etliche Stunden mit folgendem Problem herum, aber finde einfach keine Lösung:
Ich möchte mit C++ (MS Visual Studio 2010) gerne per Windows-Programm das PC-Modem ansprechen und wählen lassen. Das Modem ist an COM3.
Ich habe jetzt folgenden C++-Code, um das Modem anzusprechen und es eine Rufnr. wählen zu lassen:

HANDLE hSerial = CreateFile(TEXT("COM3"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
cout << GetLastError() << "\n";
DWORD bytesWritten = 0;
WriteFile(hSerial, "ATDT12345678\r", strlen("ATDT12345678\r"), &bytesWritten, 0);
cout << GetLastError() << "\n";

Nun kriege ich aber nach dem CreateFile-Befehl Fehler 32 ("Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird.") angezeigt, so daß das WriteFile nicht klappen kann (Fehler 6: "Das Handle ist ungültig."). Ich wüßte nicht, was sonst auf das Modem zugreifen sollte, es kommt jedes Mal, selbst nach PC-Neustart (Win XP). Mit HyperTerminal klappen die AT-Befehle hingegen problemlos.
An einem zweiten PC (auch Win XP) gibt es keine Fehler (Fehler 0: kein Fehler), aber das Modem wählt nicht, es tut "nichts". Auch an diesem PC ist das Modem an COM3 und mit HyperTerminal funktioniert es.

Ich weiß echt nicht mehr weiter, hat jemand einen hilfreichen Rat für mich?

Verzweifelte Grüße
Alexander

  1. Hallo,

    HANDLE hSerial = CreateFile(TEXT("COM3"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    cout << GetLastError() << "\n";
    DWORD bytesWritten = 0;
    WriteFile(hSerial, "ATDT12345678\r", strlen("ATDT12345678\r"), &bytesWritten, 0);
    cout << GetLastError() << "\n";

    Nun kriege ich aber nach dem CreateFile-Befehl Fehler 32 ("Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird.") angezeigt

    dann wird das Modem oder die Schnittstelle von einem anderen Prozess benutzt. ;-)

    Ich wüßte nicht, was sonst auf das Modem zugreifen sollte, es kommt jedes Mal, selbst nach PC-Neustart (Win XP).

    Eventuell der Fax Service von XP?

    Mit HyperTerminal klappen die AT-Befehle hingegen problemlos.

    Hyperterm hat vielleicht das Insiderwissen, sich mit dem Fax Service zu arrangieren.

    An einem zweiten PC (auch Win XP) gibt es keine Fehler (Fehler 0: kein Fehler), aber das Modem wählt nicht, es tut "nichts".

    Dann schließ mal probehalber einen zweiten PC anstatt des Modems an, und überprüfe mit einem Terminal auf diesem Rechner, ob der AT-Befehl auch wirklich ausgegeben wird.
    Wenn nicht, hast du immer noch ein internes Software-Problem; wenn doch, zickt das Modem selbst.

    So long,
     Martin

    --
    Soziologen sind nützlich, aber keiner will sie haben.
    Bei Informatikern ist es gerade umgekehrt.
    Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
    1. Hallo Martin,

      danke für Deine Antwort.

      dann wird das Modem oder die Schnittstelle von einem anderen Prozess benutzt. ;-)

      Ich wüßte nicht, was sonst auf das Modem zugreifen sollte, es kommt jedes Mal, selbst nach PC-Neustart (Win XP).
      Eventuell der Fax Service von XP?

      Boah, das stimmte! Obwohl nur der Windows-Faxdienst von gestartet war, ging der Zugriff aufs Modem nicht. Ich habe den Dienst deaktiviert und nun kriege ich bei beiden PCs "kein Fehler".
      Nur die Wahl funktioniert immer noch nicht.

      Dann schließ mal probehalber einen zweiten PC anstatt des Modems an, und überprüfe mit einem Terminal auf diesem Rechner, ob der AT-Befehl auch wirklich ausgegeben wird.
      Wenn nicht, hast du immer noch ein internes Software-Problem; wenn doch, zickt das Modem selbst.

      Öhm, das Modem ist bei beiden PCs ein internes ... Hätte auch kein Kabel zum Verbinden.

      Abendliche Grüße
      Alexander

      1. n'Abend!

        Eventuell der Fax Service von XP?
        Boah, das stimmte!

        manchmal ist es doch gar nicht schlecht, auf die innere Stimme zu hören. ;-)

        Obwohl nur der Windows-Faxdienst von gestartet war, ging der Zugriff aufs Modem nicht.

        Wenn der das Modem bzw. die zugehörige COM-Schnittstelle exclusiv belegt, ist das die zwangsläufige Folge.

        Nur die Wahl funktioniert immer noch nicht.

        Das ist dann wohl ein Modem-spezifisches Problem. Wartet das Modem vielleicht vor dem Wählen auf ein Freizeichen, das aufgrund eines Verkabelungsfehlers nicht kommt? Hast du mal versucht, mit einer Terminal-Session (Hyperterm) das Modem interaktiv direkt anzusprechen? Was antwortet das Modem?

        Dann schließ mal probehalber einen zweiten PC anstatt des Modems an, und überprüfe mit einem Terminal auf diesem Rechner, ob der AT-Befehl auch wirklich ausgegeben wird.
        Wenn nicht, hast du immer noch ein internes Software-Problem; wenn doch, zickt das Modem selbst.
        Öhm, das Modem ist bei beiden PCs ein internes ...

        Ah, verstehe. Dann ist es natürlich Essig mit der Direktverbindung.

        So long,
         Martin

        --
        Lieber blau machen, als sich schwarz ärgern.
        Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
        1. Moin!

          Öhm, das Modem ist bei beiden PCs ein internes ...
          Ah, verstehe. Dann ist es natürlich Essig mit der Direktverbindung.

          Er kann ja mal eine andere Schnittstelle nehmen.

          Braucht zufällig jemand ein Nullmodem-Kabel? Hier liegt noch aus DOOM- und Kirschbaum-Netz-Zeiten eines rum.

          MFFG (Mit freundlich- friedfertigem Grinsen)

          fastix

          1. Hallo,

            Er kann ja mal eine andere Schnittstelle nehmen.

            gute Idee!

            Braucht zufällig jemand ein Nullmodem-Kabel? Hier liegt noch aus DOOM- und Kirschbaum-Netz-Zeiten eines rum.

            Wozu? Das kann man sich doch aus zwei SUB-D-Steckern und drei Stückchen Klingeldraht selbst machen. Für die niedrigen Übertragungsraten im kbit-Bereich genügt das allemal.

            Ciao,
             Martin

            --
            Eine Neandertaler-Sippe sitzt in ihrer kalten Höhle. Seufzt der Stammesälteste: "Hoffentlich erfindet bald jemand das Feuer!"
            Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
            1. Moin!

              Braucht zufällig jemand ein Nullmodem-Kabel? Hier liegt noch aus DOOM- und Kirschbaum-Netz-Zeiten eines rum.

              Wozu? Das kann man sich doch aus zwei SUB-D-Steckern und drei Stückchen Klingeldraht selbst machen. Für die niedrigen Übertragungsraten im kbit-Bereich genügt das allemal.

              Mann eh! Ich wollte es los werden. Ich glaube auch es ist ein normales Kabel mit einem "Verpoler", der ein Nullmodemkabel daraus macht.

              MFFG (Mit freundlich- friedfertigem Grinsen)

              fastix

              1. Hi,

                Braucht zufällig jemand ein Nullmodem-Kabel?
                Wozu? Das kann man sich doch aus zwei SUB-D-Steckern und drei Stückchen Klingeldraht selbst machen.
                Mann eh! Ich wollte es los werden.

                vergiss es! Das ist entweder was für die "Ewig-Aufbewahren"-Schublade, oder für den Schrott.

                Ich glaube auch es ist ein normales Kabel mit einem "Verpoler"

                Es ist ein einfaches dreiadriges Kabel mit zwei SUB-D-Steckern, die 2-3, 3-2, 5-5 verbunden sind.

                Ciao,
                 Martin

                --
                Lieber eine Fliege im Porzellanladen
                als ein Elefant in der Suppe.
                Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
        2. Moin,

          Das ist dann wohl ein Modem-spezifisches Problem. Wartet das Modem vielleicht vor dem Wählen auf ein Freizeichen, das aufgrund eines Verkabelungsfehlers nicht kommt? Hast du mal versucht, mit einer Terminal-Session (Hyperterm) das Modem interaktiv direkt anzusprechen? Was antwortet das Modem?

          Nein, warten auf Wählton ist abgeschaltet.
          Mit HyperTerminal gibt's keine Probleme, das Modem meldet nach "AT" ordnungsgemäß "OK", nach "ATDT234" nimmt es ab und wählt 234, so daß das angerufene Telefon pingelt, und "quietscht" in die Leitung. Also wie gewünscht.
          Nur mit meinem Programm klappt es nicht ...

          Hm...
          Alexander

          1. Hallo,

            Wartet das Modem vielleicht vor dem Wählen auf ein Freizeichen, das aufgrund eines Verkabelungsfehlers nicht kommt?
            Nein, warten auf Wählton ist abgeschaltet.

            okay, wäre aber aufgrund deiner folgenden Beschreibung mit Terminal auch unkritisch.

            Hast du mal versucht, mit einer Terminal-Session (Hyperterm) das Modem interaktiv direkt anzusprechen? Was antwortet das Modem?
            Mit HyperTerminal gibt's keine Probleme, das Modem meldet nach "AT" ordnungsgemäß "OK", nach "ATDT234" nimmt es ab und wählt 234, so daß das angerufene Telefon pingelt, und "quietscht" in die Leitung. Also wie gewünscht.

            Also Modem geht, Leitung geht, interne Kommunikation geht.

            Nur mit meinem Programm klappt es nicht ...

            Hast du daran gedacht, dass man die COM-Schnittstelle nach dem Öffnen mit CreateFile() auch noch mit den gewünschten Parametern initialisieren muss?
             * SetupComm() setzt die Größe der Sende- und Empfangspuffer
             * SetCommState() stellt Baudrate, Anzahl der Daten- und Stoppbits, Parity ein
            Mehr mache ich in meinen Programmen doch auch nicht, wenn ich eine COM-Schnittstelle nutzen will ...

            Ciao,
             Martin

            --
            Eine Nonne kommt in den Himmel. An der Pforte fragt Petrus: "Wer bist du?" - "Ich bin die Braut Jesu." Petrus stutzt einen Moment, ruft dann nach hinten: "He Freunde, habt ihr schon gehört? Der Juniorchef will heiraten!"
            Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
            1. Hallo,

              Also Modem geht, Leitung geht, interne Kommunikation geht.

              Ja, alles wunderbar.

              Nur mit meinem Programm klappt es nicht ...
              Hast du daran gedacht, dass man die COM-Schnittstelle nach dem Öffnen mit CreateFile() auch noch mit den gewünschten Parametern initialisieren muss?
              * SetupComm() setzt die Größe der Sende- und Empfangspuffer
              * SetCommState() stellt Baudrate, Anzahl der Daten- und Stoppbits, Parity ein
              Mehr mache ich in meinen Programmen doch auch nicht, wenn ich eine COM-Schnittstelle nutzen will ...

              Ich habe folgende C++-Konstruktion:

              HANDLE hSerial;
              hSerial = CreateFile("COM3", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
              int SetupCommOK = SetupComm(hSerial, 2, 128);
              DCB dcb;
              GetCommState(hSerial, &dcb);
              dcb.BaudRate = CBR_9600;
              dcb.ByteSize = 8;
              dcb.Parity   = NOPARITY;
              dcb.StopBits = ONESTOPBIT;
              int SetCommStateOK = SetCommState(hSerial, &dcb);
              DWORD bytesWritten = 0;
              WriteFile(hSerial, "ATDT12345678\r", strlen("ATDT12345678\r"), &bytesWritten, 0);
              cout << "geschriebene Bytes: " << bytesWritten << "\n";
              CloseHandle(hSerial);

              Müßte das Modem nicht auch ohne die "Konfiguration" zumindest etwas machen? Egal, in obigem Beispiel müßte alles drin sein, was sein muß.
              Nach meinem Verständnis müßte das klappen, tut es aber nicht. Ich habe mehrere GetLastError() dazwischen verteilt, aber die liefern immer "kein Fehler" zurück.
              Die angezeigte Anzahl der geschriebenen Bytes entspricht der Länge des AT-Strings (ohne "").
              Das Modem ist und bleibt stumm. Ist in der WriteFile-Anweisung vielleicht ein Fehler drin?

              Ratlos
              Alexander

              1. Hallo Alexander,

                WriteFile(hSerial, "ATDT12345678\r", strlen("ATDT12345678\r"), &bytesWritten, 0);

                aus meinen C-Zeiten glaube ich mich daran zu erinnern, das Ausgaben erst abgeschickt wurden, wenn sie mit einem "\n" abgeschlossen wurden oder wenn der Ausgabepuffer explizit gelehrt wurde (flushbuffer o.Ä.).

                Vielleicht landen deine Ausgaben ja auch nur im Puffer und nicht im  Modem.

                Gruß, Jürgen

                1. Hallo Jürgen,

                  danke für die Idee.

                  aus meinen C-Zeiten glaube ich mich daran zu erinnern, das Ausgaben erst abgeschickt wurden, wenn sie mit einem "\n" abgeschlossen wurden

                  Das hatte ich auch schon: \r, \n, \r\n - immer das selbe: nix tut sich vom Modem.

                  oder wenn der Ausgabepuffer explizit gelehrt wurde (flushbuffer o.Ä.).

                  Es gibt flush(), aber damit bin ich auch nicht weitergekommen.

                  Noch einer eine Idee?

                  Gruß
                  Alexander

                  1. Hello,

                    Noch einer eine Idee?

                    Nur aus der Assembler- und Pascalzeit unter DOS.
                    Man musste das Modem-Steuerregister und das Modem-Statusregister gezielt ansprechen.

                    Hier ein Stück davon in Pascal-Code. Das Assemblerbeispiel finde ich gerade nicht.
                    Übrigens funktioniert dieses alte Programm, wozu das Stück gehört, immer noch in der Command-Box von WinXP.

                    Die C-Funktionen SetupComm() und SetCommState() sollten das aber eigentlich besorgen.

                    Wenn Du eine reine Windowslösung (ab 95b) haben willst, musst Du aber die Schnittstellen erst vom OS freigeben lassen, wenn Du sie selber ansprechen willst auf einer tieferen Ebene. Das habe ich leider vergessen, wie das ging. Aber solange Windows selber auf der COM-Schnittstelle sitzt, lässt es Dein Programm nicht ran.

                    procedure InstCom(ComNr:byte;Direct:Char);

                    var   BaudMSB    : byte;
                          BaudLSB    : byte;
                          LtgSteuReg : byte;
                          LtgStatReg : byte;
                          Zeichen    : byte;

                    begin
                      IntMskReg:=Port[$21];
                      Port[$21]:=(IntMskReg or $18);        { IRQ von COM1 und COM2 ausmaskieren }

                    case ComNr of
                        1: begin
                             ComBasis:=Com1Basis;
                             GetIntVec($0C,OldIntComX);               { IVT 13 = IRQ 4 }
                             SetIntVec($0C,Addr(Receive));
                             Port[$21]:=(IntMskReg and $EF);          { IRQ von COM1 zulassen }
                           end;
                        2: begin
                             ComBasis:=Com2Basis;
                             GetIntVec($0B,OldIntComX);               { IVT 12 = IRQ3 }
                             SetIntVec($0B,Addr(Receive));
                             Port[$21]:=(IntMskReg and $F7);          { IRQ von COM2 zulassen }
                           end;
                        3: begin
                             ComBasis:=Com3Basis;
                             GetIntVec($0D,OldIntComX);               { IVT 14 = IRQ5 }
                             SetIntVec($0D,Addr(Receive));
                             Port[$21]:=(IntMskReg and $DF);          { IRQ von COM3 zulassen }
                           end;
                           { Um Intr-Anforderung zuzulassen, muá das Bit auf 0 stehen !!}
                      end;

                    {-------Baudrate einstellen---------->  Baudrate = 1.8432MHz / (16*Teiler)
                                                         ==>  Baudrate = 115200kHz / Teiler }
                      BaudMSB := (115200 div Preset.Baud div 256);
                      BaudLSB := (115200 div Preset.Baud);

                    Port[ComBasis+3]:=128;                { LtgSteuReg zum Einstellen der
                                                              Baud-Rate vorbereiten }
                      Port[ComBasis]:=BaudLSB;              { LSB des Teilers für Baudrate }
                      Port[ComBasis+1]:=BaudMSB;            { MSB des Teilers für Baudrate }

                    {-------Leitungs-Steuerregister setzen -------------}
                      LtgSteuReg := 0
                        or (Preset.Bit-5)                   { Anzahl der šbertragungs-Bits}
                        or ((Preset.Stop-1)*4);             { Anzahl der Stopbits setzen }

                    case Preset.Parity of
                        'K': null;                          { keine Paritätsprüfung }
                        'G': LtgSteuReg:=LtgSteuReg or 24;  { Gerade Parit„t einstellen }
                        'U': LtgSteuReg:=LtgSteuReg or 8;   { Ungerade Parit„t einstellen }
                      end;
                      Port[ComBasis+3]:=LtgSteuReg;         { Leitungssteuerreg. setzen für
                                                              Datenübertragung }

                    {-------Interrupt-Aktivierungs-Register setzen -----}
                      if (Direct in ['E','D']) then
                        Port[ComBasis+1]:=1                 { IntReq wenn Zeichen vorliegt }
                      else
                        Port[ComBasis+1]:=0;                { kein IntReq }

                    {-------definierte Startwerte herstellen -----------}
                      LtgStatReg:=Port[ComBasis+5];         { LtgStatReg einmal auslesen }
                      Zeichen:=Port[ComBasis];              { COM2 Empfangs-Halteregister ausl. }
                      Port[$20]:=$20;                       { EOI-Signal einmal aussenden }

                    {-------Modem-Steuerregister setzen ----------------}
                      if (Direct in ['E','D']) then
                        Port[ComBasis+4]:=11                { IntReq EIN }
                      else
                        Port[ComBasis+4]:=3;                { IntReq AUS }

                    ComSelect:=ComNr;
                    end;

                    Liebe Grüße aus dem schönen Oberharz

                    Tom vom Berg

                    --
                     ☻_
                    /▌
                    / \ Nur selber lernen macht schlau
                    http://bergpost.annerschbarrich.de
                    1. Hallo,

                      ich hab's nun hingekriegt. Nach einigem Gucken und Probieren funktionierte es. Ich weiß zwar nicht, woran genau es lag, aber es geht jetzt.

                      Danke für die Tips.

                      Alexander