Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   [C] Zeichenfolge aus Funktion zurückgeben (https://www.delphipraxis.net/76994-%5Bc%5D-zeichenfolge-aus-funktion-zurueckgeben.html)

Luckie 13. Sep 2006 09:57


[C] Zeichenfolge aus Funktion zurückgeben
 
Folgender Code:
Code:
#include <stdio.h>
#include <windows.h>


TCHAR* SysErrorMessage(int ErrorCode) {
   TCHAR szBuf[80];
    LPVOID lpMsgBuf;
    DWORD dw = GetLastError();

    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf,
        0, NULL );

   wsprintf(szBuf, (LPTSTR)lpMsgBuf);
   LocalFree(lpMsgBuf);
   return szBuf;    
}

int main(int argc, char* argv[])
{
   printf(SysErrorMessage(5));
   return 0;
}
Leider gelingt es mir nicht eine ganz normale Zeichenfolge beliebiger Länmge aus der Funktion zurückzugeben, so dass ich sie mit printf ausgeben kann.

Zusatzaufgabe: Wie mache ich das ganze Unicode sicher?

Vjay 13. Sep 2006 10:02

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Benutzt du dort den GNU-C Compiler?

Mh, ohne jetzt eine genaue Ahnung zu haben, würde ich versuchen einen pChar zurückzugeben.

Grad mal in die Hilfe zu FormatMessage geguckt:

Zitat:

pBuffer

Points to a buffer for the formatted (and null-terminated) message. If dwFlags includes FORMAT_MESSAGE_ALLOCATE_BUFFER, the function allocates a buffer using the LocalAlloc function, and places the address of the buffer at the address specified in lpBuffer.
Denke ich weiss worauf du hinaus willst, aber Standard-C hat nicht die Super-Delphi-Stringbehandlung.

ste_ett 13. Sep 2006 10:04

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Code:
#include <stdio.h>
#include <windows.h>


TCHAR* SysErrorMessage(int ErrorCode) {
   TCHAR szBuf[80];
   LPVOID lpMsgBuf;
//   DWORD dw = GetLastError();
   DWORD dw = ErrorCode;

   FormatMessage(
      FORMAT_MESSAGE_ALLOCATE_BUFFER |
      FORMAT_MESSAGE_FROM_SYSTEM,
      NULL,
      dw,
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      (LPTSTR)&lpMsgBuf,
      0, NULL );

   wsprintf(szBuf, (LPTSTR)lpMsgBuf);
   LocalFree(lpMsgBuf);
   return szBuf;    
}

int main(int argc, char* argv[])
{
   printf("%s", SysErrorMessage(5));
   return 0;
}
- übergebenen Wert aus "ErrorCode" wird jetzt zur Umwandlung genommen
- Ausgabe geändert in "printf("%s", SysErrorMessage(5));"

Ich würde einen Char-Array als Parameter übergeben, in den du schreibst, oder du holst Speicher innerhalb der Funktion und gibst ihn nach dem Aufrufen wieder frei. :)

Luckie 13. Sep 2006 10:20

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Zitat:

Zitat von ste_ett
Ich würde einen Char-Array als Parameter übergeben, in den du schreibst, oder du holst Speicher innerhalb der Funktion und gibst ihn nach dem Aufrufen wieder frei. :)

So komplizierte Aufrufe wollte ich eigentlich vermeiden.

Deine Version kompiliert jetzt zwar, aber es wird nur Datenmüll ausgegeben. Später will ich die Funktion SysErrorMessage auch bei einer Messagebox oder so benutzen, da geht das ja dann nicht mehr mit printf("%s", ...);.

Flocke 13. Sep 2006 10:20

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Ganz grober Schnitzer: szBuf liegt auf dem Stack, ist also nach dem Aufruf der Funktion eigentlich nicht mehr gültig. Wenn der Inhalt noch drin steht, dann hast du Glück. Ein erster Bugfix wäre, static TCHAR szBuf[80]; zu benutzen.

Allerdings ist es in C üblich, den Ergebnisparameter zusammen mit der maximalen Länge zu übergeben, wie ste_ett schon schrieb.

Luckie 13. Sep 2006 10:24

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Also so was:
Code:
void SysErrorMessage(int ErrorCode, char* Buffer, int lenBuffer)
Nur bin ich in C noch nicht so tritt fest, wie müsste denn dann die Implementation und der Aufruf aussehen? Und ambesten noch Unicode fähig. Wir wollen ja gleich up to date sein. ;)

ste_ett 13. Sep 2006 10:30

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Code:
#include <stdio.h>
#include <windows.h>

DWORD SysErrorMessage(const int ErrorCode, wchar_t* szBuf, const DWORD ArrayLength)
{
   DWORD result = 0;
   LPVOID lpMsgBuf = NULL;
   DWORD dw = ErrorCode;

   result = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw,
                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&lpMsgBuf, 0, NULL);

   if (result <= ArrayLength)
   {
      wsprintf(szBuf, (LPWSTR)lpMsgBuf);
   }
   else
   {
      result = (DWORD)-1; // ErrCode
   }

   LocalFree(lpMsgBuf);

   return result;
}

int main(int argc, char* argv[])
{
   TCHAR szBuf[80];
   ZeroMemory(szBuf, sizeof(szBuf));

   if (SysErrorMessage(5, szBuf, sizeof(szBuf) / 2))
   {
      wprintf(L"%s", szBuf);
   }

   return 0;
}
z.B. so :)

Flocke 13. Sep 2006 10:31

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Etwa so:
Code:
TCHAR *
SysErrorMessage (DWORD dwErrorCode, TCHAR *pszBuf, int nLenBuf)
{
  FormatMessage(
    FORMAT_MESSAGE_FROM_SYSTEM | (pszBuf ? FORMAT_MESSAGE_ALLOCATE_BUFFER : 0),
    NULL,
    dwErrorCode ? dwErrorCode : GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    pszBuf ? pszBuf : (LPTSTR)&pszBuf,
    pszBuf ? nLenBuf : 0,
    NULL);
  return pszBuf;
}
// Nachtrag: noch erweitert

Luckie 13. Sep 2006 10:45

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Ah, ja die Version von ste_ett funktioniert und ich habe sie verstanden. Aber wäre es nicht sinnvoll die benötigte Länge des Buffers zurückzugeben, so dass man im Bedarfsfall entsprechend mehr Speicher reservieren kann? aslo:
Code:
len = SysErrorMessage(5, NULL, 0);
GetMem(szBuff, len)
SysErrorMessage(5,szBuf, len);
FreeMem(szBuf);
Das ist jetzt Delphi Pseudocode.

Und wie kann ich den Code in eine eigene Quellcodedatei auslagern? Ich habe ihn in eine eigene Datei kopiert MpuTools.cpp und eine entsprechende headerdatei angelegt: MpuTools.h, die ich dann mit include eingebunden habe:

Code:
#include <stdio.h>
#include <windows.h>
#include "MpuTools.h"

int main(int argc, char* argv[])
{
   TCHAR szBuf[80];
   ZeroMemory(szBuf, sizeof(szBuf));

   if (SysErrorMessage(5, szBuf, sizeof(szBuf)) >0)
   {
      wprintf(L"%s", szBuf);
     MessageBoxW(0, szBuf, L"Test", 0);
   }

   return 0;
}
Das mag der Compiler jedoch nicht:
Zitat:

Fehler 1 error C2144: Syntaxfehler: 'int' sollte auf ';' folgen c:\dokumente und einstellungen\mp\eigene dateien\visual studio 2005\projects\mputools\mputools_test\mputools_test .cpp 5
OK, in der Header-Datei hat ein Semikolon gefehlt. Jetzt bekomme ich aber die fehlermeldung:
Zitat:

Fehler 1 error LNK2019: Verweis auf nicht aufgelöstes externes Symbol ""unsigned long __cdecl SysErrorMessage(int,wchar_t *,unsigned long)" (?SysErrorMessage@@YAKHPA_WK@Z)" in Funktion "_main". MpuTools_Test.obj
:gruebel:

Luckie 13. Sep 2006 13:10

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
OK, das Problem ist gelöst: Ich musste noch die dateien zum Projekt hinzufügen. Ich dachte das passiert irgendwie automatisch, wenn ich die entsprechende Header-Datei einbinde. Damit wäre alles geklärt. Besten Dank für eure Hilfe.

Flocke 13. Sep 2006 14:04

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Zitat:

Zitat von Luckie
Ah, ja die Version von ste_ett funktioniert und ich habe sie verstanden.

Ok, dann muss ich wohl ein wenig erläutern :???:

Code:
TCHAR *
SysErrorMessage (DWORD dwErrorCode, TCHAR *pszBuf, int nLenBuf)
{
  FormatMessage(
    FORMAT_MESSAGE_FROM_SYSTEM | (pszBuf ? FORMAT_MESSAGE_ALLOCATE_BUFFER : 0),
    NULL,
    dwErrorCode ? dwErrorCode : GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    pszBuf ? pszBuf : (LPTSTR)&pszBuf,
    pszBuf ? nLenBuf : 0,
    NULL);
  return pszBuf;
}
Diese Routine kannst du auf variable Art aufrufen, bei C++ könntest du sogar noch Defaultwerte für die Parameter angeben.
  • Wenn du dwErrorCode übergibst, dann liefert sie die Beschreibung eben dafür, ansonsten für den letzten aufgetretenen Fehler (GetLastError()) (das Konstrukt "a ? b : c" bedeutet "wenn a <> 0 dann b sonst c").
  • Wenn du einen Puffer bereitstellst und in pszBuf übergibst, dann nimmt er den (und nLenBuf), ansonsten lässt er FormatMessage den Speicher selbst belegen.
  • Der Rückgabewert ist ein TCHAR *, damit du die Funktion direkt als Argument für MessageBox o.ä. benutzen kannst.
Beispiel:
Code:
#define countof(X) (sizeof(X) / sizeof(X[0]))

int
main (int argc, char **argv)
{
  // Statischer Puffer mit fester Länge, Fehlermeldung 5
  TCHAR szBuf[80];
  printf(_T("%s\n"), SysErrorMessage(5, szBuf, countof(szBuf)));

  // Dynamischer String, aktuelle Fehlermeldung
  LPTSTR pszBuf;
  pszBuf = SysErrorMessage(0, NULL, 0);
  printf(_T("%s\n"), pszBuf);
  LocalFree(pszBuf);

  return 0;
}

Luckie 13. Sep 2006 14:07

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Zitat:

Zitat von Flocke
Diese Routine kannst du auf variable Art aufrufen, bei C++ könntest du sogar noch Defaultwerte für die Parameter angeben.
  • Wenn du einen Puffer bereitstellst und in pszBuf übergibst, dann nimmt er den (und nLenBuf), ansonsten lässt er FormatMessage den Speicher selbst belegen.

Ah, das ist sehr gut. :thumb:

Er meint jetzt aber dass _T nicht gefunden wurde:
Zitat:

Fehler 1 error C3861: "_T": Bezeichner wurde nicht gefunden. c:\dokumente und einstellungen\mp\eigene dateien\visual studio 2005\projects\mputools\mputools_test\mputools_test .cpp 9
Lasse ich es weg gibt er nichts aus und die Messagebox bleibt leer.

Luckie 13. Sep 2006 14:40

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Habs gelöst, man muss #include <tchar.h> inkludieren. Nur bleibt meine Messagebox leer und bei printf kommt:
Zitat:

Fehler 1 error C2664: 'printf': Konvertierung des Parameters 1 von 'const wchar_t [4]' in 'const char *' nicht möglich c:\dokumente und einstellungen\mp\eigene dateien\visual studio 2005\projects\mputools\mputools_test\mputools_test .cpp 10
Code:
#include <stdio.h>
#include <windows.h>
#include <tchar.h>
#include "MpuTools.h"

int main(int argc, char* argv[])

   // Statischer Puffer mit fester Länge, Fehlermeldung 5
   TCHAR szBuf[80];
   //printf(_T("%s\n"), SysErrorMessage(5, szBuf, countof(szBuf)));

   // Dynamischer String, aktuelle Fehlermeldung
   LPTSTR pszBuf;
   pszBuf = SysErrorMessage(0, NULL, 0);
   //printf(_T("%s\n"), pszBuf);
   LocalFree(pszBuf);

   MessageBoxW(0, SysErrorMessage(5, NULL, 0), L"Test", 0);

   return 0;
}
So:
Code:
int main(int argc, char* argv[])

   // Dynamischer String, aktuelle Fehlermeldung
   LPTSTR pszBuf;
   pszBuf = SysErrorMessage(0, NULL, 0);
   MessageBoxW(0, pszBuf, L"Test", 0);
   //printf(_T("%s\n"), pszBuf);
   LocalFree(pszBuf);

   // Statischer Puffer mit fester Länge, Fehlermeldung 5
   TCHAR szBuf[80];
   MessageBoxW(0, SysErrorMessage(5, szBuf, countof(szBuf)), L"Test", 0);

   return 0;
}
Ist die erste Messagebox leer und die zweite zeigt nur viele quadrate an. :?

Flocke 13. Sep 2006 15:10

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Sorry Luckie.

1. Ich hätte für printf natürlich _tprintf nehmen müssen. Die ganzen _t-Funktionen sind auch in tchar.h definiert.
2. Das MessageBoxW sollte eigentlich nicht nötig sein. Hast du UNICODE definiert? Übersetzt du mit dem GCC oder MSC?

// Nachtrag

Hab einen Dreher dringehabt :oops: (kommt davon wenn man's nicht ausprobiert)
Code:
TCHAR *
SysErrorMessage (DWORD dwErrorCode, TCHAR *pszBuf, int nLenBuf)
{
  FormatMessage(
    FORMAT_MESSAGE_FROM_SYSTEM | (pszBuf ? 0 : FORMAT_MESSAGE_ALLOCATE_BUFFER),
    NULL,
    dwErrorCode ? dwErrorCode : GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    pszBuf ? pszBuf : (LPTSTR)&pszBuf,
    pszBuf ? nLenBuf : 0,
    NULL);
  return pszBuf;
}

Luckie 13. Sep 2006 15:28

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Ah, das erklärt einiges. ;) Besten Dank.

Olli 7. Okt 2006 19:37

Re: [C] Zeichenfolge aus Funktion zurückgeben
 
Die Frage ist noch als offen markiert.

Hinzufügen möchte ich auch, daß der gute Stil erfordert, daß man absolut niemals (s)printf, ebenso wie strcat, strcpy usw. benutzen sollte (auch ich halte mich nicht immer dran ...). Warum sollte bekannt sein, wenn man ab und zu die Meldungen über Verwundbarkeiten in Software verfolgt. Alle diese Funktionen achten nicht auf die Länge des Puffers - daher kommt es gehäuft beim Einsatz dieser Funktionen zu Sicherheitslücken. Es gibt für die meisten dieser Funktionen eine Version mit Längenüberprüfung. Von der Typunsicherheit habe ich noch nichtmal geredet.

Unter C++ sind sowieso die Streams vorzuziehen, da du die Typsicherheit schon während des Kompilierens gewährleistest. Ansonsten machst du nichts anderes als ein C-Programm mit einem C++-Compiler zu kompilieren ... :zwinker:


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:20 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz