Format-Probleme mit übergabe eines Strings an eine Funktion. (Auch Heap-Block Problem)
-
Tja, wo fängt man am besten an?
1. LPWSTR ist ein Zeiger!
2. malloc will als Parameter die Größe des zu reservierenden Speichers in Byte! len - der Parameter, den Du übergibst - ist laut Dokumentation zu MultiByteToWideChar aber nur die Anzahl der zu reservierenden Zeichen! Daraus folgt, dass Du viel zu wenig Speicher reservierst!Deshalb:
LPWSTR unicodestring = malloc(len * sizeof(WCHAR));
...
free(unicodestring);
...
Edit:
Für C++ muss natürlich das Ergebnis von malloc gecastet werden:
LPWSTR unicodestring = (LPWSTR)malloc(len * sizeof(WCHAR));in C++ könntest Du allerdings auch statt malloc/free new[]/delete[] benutzen ...
-
Im konkreten Fall, wo der Eingabestring ja scheinbar nie länger als 79 Zeichen sein darf, reicht auch ein
wchar_t unicodestr[80];
free() entfällt dann ersatzlos. Es muss dann aber natürlich sichergestellt sein, dass 79 Zeichen wirklich immer ausreichen!
Eine Aufstellung der Windows-Datentypen findet sich hier. Generell ist alles, was mit LP anfängt, im WinAPI ein Zeigertyp (LP = Long Pointer, LPWSTR = Long Pointer to Wide STRing. Das "Long" in "Long Pointer" ist ein Überbleibsel aus der Zeit, als zwischen Nah- und Fernzeigern unterschieden wurde und hat heute keine Bedeutung mehr).
Allerdings: Die Arbeit mit verschiedenen Zeichensätzen ist ein ziemliches Gefrickel. Sofern es dir vernünftig möglich ist, wäre es für den Umgang mit COM wahrscheinlich am einfachsten, das gleich mit wchar_t zu machen. Im konkreten Fall (ich hoffe, ich vertu mich jetzt nicht; ich hab hier kein Windows, um das zu testen):
#include <stdio.h> #include <stdlib.h> #include <conio.h> #include <sapi.h> int ausgabe(LPCWSTR input) { ISpVoice *pVoice = NULL; HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice); if(SUCCEEDED(hr)) { hr = pVoice->Speak(input, 0, NULL); pVoice->Release(); return TRUE; } return FALSE; } int main() { bool ende = false; // Der COM-ORB muss nur einmal pro Thread initialisiert und geschlossen // werden. Wahrscheinlich kann man auch ein SpVoice-Objekt mehrmals benutzen, // aber im SAPI kenne ich mich nicht aus, daher lasse ich das hier. if(FAILED(::CoInitialize(NULL)) { return -1; } do { // _kbhit-Prüfung ist hier nicht notwendig. Du willst ja eh auf einen // Tastendruck warten, also kann _getch() ruhig blockieren. char ch = _getch(); if(ch == '\0') ch = _getch(); switch(ch) { case 'k': puts ( "Taste K gedrueckt."); ausgabe(L"Taste K gedrueckt."); break; case 'm': puts ( "Taste M gedrueckt."); ausgabe(L"Taste M gedrueckt."); break; case VK_ESCAPE: ende = true; break; } } while(!ende); ::CoUninitialize(); system("PAUSE"); }
-
DaRe schrieb:
Naja, es scheint noch zu Fehlern zu kommen, oder?
Nein, gar keine. Selbst wenn ich alle Warnungen anzeigen lasse gibt es keine Warnungen. Also die Einstellung nach Level4 Warnstufe.
Naja bis auf iwas mit dem getchar und einer umwandlung von iwas in iwas.Belli schrieb:
Daraus folgt, dass Du viel zu wenig Speicher reservierst!
Das erklärt warum ich, um ein Problem zu lösen,
len=len*10;
unter die deklaration geschrieben habe.
@seldon: Danke das werde ich mal ausprobieren. Ich befürchte aber Probleme da ich variabeln in einen anderen String schreibe mit sprintf_s. Es gibt doch immer Probleme.
EDIT: Ja da gibts Probleme. Durch herumprobieren und googlen konnte ich das Problem noch nicht lösen. Hier der Code wie er jetzt aussieht:#include <stdio.h> #include <stdlib.h> #include <sapi.h> #include <time.h> #include <conio.h> int ausgabe(LPCWSTR input) { ISpVoice *pVoice = NULL; HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice); if(SUCCEEDED(hr)) { hr = pVoice->Speak(input, 0, NULL); pVoice->Release(); return TRUE; } return FALSE; } int main() { bool ende = false; LPCWSTR uhrzeit1[80]; // Der COM-ORB muss nur einmal pro Thread initialisiert und geschlossen // werden. Wahrscheinlich kann man auch ein SpVoice-Objekt mehrmals benutzen, // aber im SAPI kenne ich mich nicht aus, daher lasse ich das hier. if(FAILED(::CoInitialize(NULL))) { return -1; } do { // _kbhit-Prüfung ist hier nicht notwendig. Du willst ja eh auf einen // Tastendruck warten, also kann _getch() ruhig blockieren. char ch = _getch(); //Warnung: Konvertierung von 'int' in 'char'. Nachgucken warum. if(ch == '\0') ch = _getch(); //Warnung: Konvertierung von 'int' in 'char'. Nachgucken warum. switch(ch) { case 'k': puts ( "Taste K gedrueckt."); ausgabe(L"Taste K gedrueckt."); break; case 'm': puts ( "Taste M gedrueckt."); ausgabe(L"Taste M gedrueckt."); break; case 't': struct tm *newtime; time_t long_time; time( &long_time ); newtime = localtime( &long_time ); //Z.B.: printf("Uhrzeit = %d:%d:%d", newtime->tm_hour, newtime->tm_min, newtime->tm_sec); swprintf_s(uhrzeit1, "Es ist jetzt %d Uhr %d\0",newtime->tm_hour, newtime->tm_min); printf(uhrzeit1); ausgabe(uhrzeit1); swprintf_s(uhrzeit1, " und %d Sekunden.\n\0", newtime->tm_sec);//String geteilt übergeben, da es mit "malloc" zu Speicher-Zugriffsverletzungen kommt. Noch nicht geändert. printf(uhrzeit1); ausgabe(uhrzeit1); //Das Problem hat was mit Zahlen zu tun ... break; //Entscheiden ob Sekunden notwendig sind. case 'd': struct tm *newdate; time_t long_date; time( &long_date ); newdate = localtime( &long_date ); //Z.B.: printf("Uhrzeit = %d:%d:%d", newtime->tm_hour, newtime->tm_min, newtime->tm_sec); sprintf_s(uhrzeit1, "Heute ist der %d.%d.%d.\n\0",newdate->tm_mday, newdate->tm_mon+1, newdate->tm_year+1900); printf(uhrzeit1); ausgabe(uhrzeit1); break; case VK_ESCAPE: ende = true; break; } } while(!ende); ::CoUninitialize(); }
MfG
EDIT: Boah Leute! Dauernd bekomme ich Probleme mit inkompatiblen Typen. Was für eine Sprache ist denn das? Warum ist das so kompliziert gemacht? Bei mir gibts nur Zahlen und Buchstaben. Das sieht für mich aus als wenn immer wieder irgendein Problem aufkam, für dessen Lösung man ein weiteres Format benötigte und einbaute, bis am Ende 1024 verschiedene Formate vorhanden sind, von denen ICH eines nicht in das andere konvertiert bekomme...
"double ist nicht mit const char kompatibel"
"const char ist nicht mit LPCWSTR kompatibel"
"LPCWSTR ist mit garnichts kompatibel, ÄtschiBätch!"Ist hier in der IDE irgendwas falsch eingstellt? Kann sich denn nichts einfach mal so in etwas anderes konvertieren ...
-
Also, hier muss irgendwas falsch sein. Ich habe gerade Zwei Programme aus einem MS Visual c++ 2008 Projekt herauskopiert und versucht sie zu kompilieren.
Erstmal musste ich <stdlib.h> zu den includes schreiben damit er überhaupt "system("CLS")" erkennt. Früher reichten <stdio.h> und <string.h>
Dann meckert er bei strcat jetzt plötzlich: "Zu viele Argumente im Funktionsaufruf" obwohl das hier früher ohne Probleme ging: strcat(pos[ze], " ", zf++); (zf ist eine Zähl-variable)
Er kompiliert sie ja sogar ohne Warnungen deshalb, meckert aber in der IDE herum.
Dann musste ich Zähl-Variabeln ändern und aus sprintf-befehle Variabeln heraus holen, die darin mit 1 addiert werden und darunter schreiben, weil er sonst schon bevor er das was in der Variable steht in den String schreibt, sie mit 1 addiert.Und das bei zwei verschiedenen Programmen!
Heute erscheint mir manches allerdings Logisch, doch früher muss es auch ohne alle diese änderungen geklappt haben. Hat sich denn die Sprache verändert in der zeit von 2008 bis 2010?
Wie schlimm ist das erst wenn richtig Komplexe Programme sind ...
-
strcat erwartet 2 Parameter
strncat erwartet 3 ParameterDer erste Parameter ist auch noch ein Zeiger(sieht mir nach nem char aus)?
strcat(pos[ze], " ", zf++);
-
Ja, ist ein Zeiger.
while(zf!=zb) strcat(pos[ze], " ", zf++);
zf ist eine variabel, kein Parameter, die nur darin steht, damit ich diese {} Klammern nicht schreiben muss. Also wie da unten in dem einen Beispiel.
Es funktioniert ja so auch, aber warum gibt es keine Fehler wenn er denn schon meckert?Hier mal das andere etwas genauer:
Früher sah das so aus:if(zc<=9) sprintf(spa[zc], " %i", zc++); else sprintf(spa[zc], "%i", zc++);
Heute geht nur noch das:
if(zc<=9) { sprintf(spa[zc], " %i", zc); zc++; } else { sprintf(spa[zc], "%i", zc); zc++; }
Weil sonst, wie gesagt, schon zu früh zc um eins erhöht wird. Also im alten IDE:
zc=1, in das spa-Array wird auf Position 1 " 1" geschrieben.
Im Neuen IDE wird auf Position 1 schon " 2" geschrieben. DEshalb die Änderungen.
Das ist kein Codegemansche von mir, das ging früher wirklich so.Da muss isch doch was geändert haben. Aber egal.
Wie Löse ich das Problem ein Paar Posts weiter oben?
MfG
-
FreakySmiley schrieb:
Früher sah das so aus:
if(zc<=9) sprintf(spa[zc], " %i", zc++); else sprintf(spa[zc], "%i", zc++);
Heute geht nur noch das:
if(zc<=9) { sprintf(spa[zc], " %i", zc); zc++; } else { sprintf(spa[zc], "%i", zc); zc++; }
Das nehme ich dir nicht ab.
Je nachdem, wie spa und zc konkret definiert sind, muss dass jeder C Compiler übersetzen.
Schreibe mal ein eigenes main mit nur o.g. Code, übersetze dann und nenne die konkreten Compilerausgaben.
-
Hi,
was für Compilerausgaben willst du denn sehen? Zu dem Problem mit "sprintf" gibt es keine Compilerausgaben. Nur zu dem Problem mit "strcat".
Ich könnte den Code hier hin schreibenIch könnte mal den komletten alten Code, der früher funktioniert hat (Wo ich nur <stdlib.h> includiert habe damit diese "system" Aufrufe noch funktionieren.) und denk kompletten neuen Code hier reinschreiben, damit ihr das selbst testen könnt.
Aber das wird ein langer Post.
MfG
PS: Schon eine Idee zu dem Problem im Post vom 12:53:16 30.10.2011 ?
-
FreakySmiley schrieb:
PS: Schon eine Idee zu dem Problem im Post vom 12:53:16 30.10.2011 ?
Vielleicht ist es einfacher, wenn Du bei der Version davor bleibst. Reserviere einfach genug Speicher für den UNICODE-String, wie ich es Dir gezeigt habe und lass den Rest im MBCS-Format:
int ausgabe(const char *ansistr) { int i=0; int len = MultiByteToWideChar(CP_ACP, 0, ansistr, -1, NULL, 0); LPWSTR unicodestr = (LPWSTR)malloc(len * sizeof(WCHAR)); // free() nicht vergessen!?? MultiByteToWideChar(CP_ACP, 0, ansistr, -1, unicodestr, len); ISpVoice * pVoice = NULL; if (FAILED(::CoInitialize(NULL))) return FALSE; HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice); if( SUCCEEDED( hr ) ) { hr = pVoice->Speak(unicodestr, 0, NULL); pVoice->Release(); pVoice = NULL; } free(unicodestr); //Verursacht Heap-Block fehler. ::CoUninitialize(); return TRUE; }
-
Hm, das mag wohl stimmen.
Nachdem ich wieder einmal mein C-Buch zu rate gezogen habe, verstehe ich auch was genau deine Lösung macht.
Danke.Dann gibts jetzt nur noch das Problem mit den veränderten strcat und sprintf. Kann es sein das ich schon mit C++11 arbeiten und sich deshalb was geändert hat? Ich habe Visual c++ Express nämlich erst vor einer Woche oder so intalliert, da war das ja schon draußen.
Allerdings, fällt mir ein, lautet der Name der Sourcecode-Dateien xxxx.c und nicht xxxx.cpp. Da ändert sich doch auch das Verhalten von Visual c++, oder? ALos soltle doch die umstellung auf c++11 keine Auswirkung ahben auf .c Programme. Und darin ist nur C, kein C++.MfG