![]() |
Unicode Eingabe einlesen
Ich versuche gerade eine Eingabe von der Konsole zu lesen:
Code:
Aber wenn er die Eingabe ausgeben soll, kommt es zu einer Zugriffsverletzung. Was mache ich da falsch? Die Eingabe soll spätermal an eine Funktion übergeben werden.
#include "stdafx.h"
#include <windows.h> #define INFO _T("Ausgabe der SIDs zu einem principal\n") #define PRINCIPAL _T("Principal (z.B. Benutzername): ") int _tmain(int argc, _TCHAR* argv[]) { PWSTR principal; wprintf(INFO); wprintf(PRINCIPAL); wscanf(L"%s", &principal); wprintf(L"%s\n", principal); getchar(); return 0; } |
Re: Unicode Eingabe einlesen
Zeile12: Welche Adresse liefert &principal?
Oben arbeitest du mit #define, vermute mal das es dadurch knallt. (ungetestet) |
Re: Unicode Eingabe einlesen
Ha! ein Abtrüniger C-Programmierer.
Die Strafe folgt sogleich:
Code:
Mit Delphi wäre das nicht passiert. :-)
PWSTR principal; // das ist nur ein Zeiger, für den niemand einen Speicherplatz reserviert hat
|
Re: Unicode Eingabe einlesen
Auch wenn ich das ändere geht es nicht. Aber so geht es:
Code:
Das ganze muss ich jetzt aber an eine Funktion übergeben: LookupAccountName die ich in einer Funktion kapseln will:
wchar_t principal[80];
wprintf(INFO); wprintf(QUERYINPUT); wscanf(L"%s", &principal); wprintf(L"%s\n", principal); getchar(); return 0; Das soll dann so aussehen:
Code:
Bekomme aber noch zwei Fehlermeldungen:
DWORD GetStrSID(LPTSTR server, LPTSTR principal, wchar_t *StrSID)
{ wprintf(principal); // SID ermitteln und in lesbare Form umwandeln // in StrSID zurückgeben return GetLastError(); } int _tmain(int argc, _TCHAR* argv[]) { wchar_t principal[80]; wchar_t *StrSID; int LastError; wprintf(INFO); wprintf(QUERYINPUT); wscanf(L"%s", &principal); wprintf(L"%s\n", principal); LastError = GetStrSID(NULL, principal, StrSID); if (LastError == 0) { wprintf(L"%s", StrSID); } else { wprintf("%i", LastError); } getchar(); return 0; } Zitat:
Zitat:
|
Re: Unicode Eingabe einlesen
Dass DWORD und int einen Unterschied machen und warum, erklaere ich jetzt nicht nochmal.
Bei
Code:
fehlt mir irgendwie der Unicode-Literal als erster Parameter. Wie waere es mit
wprintf("%i", LastError);
Code:
...?
wprintf(L"%i", LastError);
... warum du echtes Unicode mit der gemischten Form (LPTSTR) zusammen benutzt, erschliesst sich mir auch nach mehrmaligem Hingucken noch nicht ganz, aber vielleicht kannst du es erklaeren. Genau wie den Sinn gemischt Typen aus den Windows-Headern und native C++-Typen zu benutzen ... :gruebel: Wenn man _UNICODE/UNICODE nicht definiert hat, warum sollte dann bspw. die Zeile
Code:
funktionieren, wenn doch principal vom Typ LPTSTR (schon an die konstante Variante LPCTSTR gedacht?) ist und damit zu LPSTR (sprich PChar) wird?! Stattdessen solltest du eben LPWSTR oder besser LPCWSTR benutzen. Und ueberhaupt mal weniger Windowstypen und C++-Typen mischen (sprich: disziplinierter programmieren), damit es zu solchen Fehlern erst garnicht kommen kann.
wprintf(principal);
Wenn man die Adresse eines Zeichenarrays haben will, muss man auch keinen Adressoperator voranstellen. Hier meine leicht korrigierte Variante. WinDiff wirste ja haben ...
Code:
Uebrigens empfiehlt sich beim Arbeiten mit nullterminierten Strings auch das Ausnullen des Puffers (principal).
DWORD GetStrSID(LPCWSTR server, LPCWSTR principal, LPWSTR &StrSID)
{ wprintf(principal); // SID ermitteln und in lesbare Form umwandeln // in StrSID zurückgeben return GetLastError(); } int __cdecl _tmain(int argc, _TCHAR *argv[]) { WCHAR principal[80], *StrSID = principal; DWORD LastError; // wprintf(INFO); // wprintf(QUERYINPUT); <--- warum die auskommentiert sind sollte klar sein wscanf(L"%s", principal); wprintf(L"%s\n", principal); LastError = GetStrSID(NULL, principal, StrSID); if (LastError == 0) { wprintf(L"%s", StrSID); } else { wprintf(L"%i", LastError); } getchar(); return 0; } Last but not least: da du Arrays equivalent zu Pointern benutzen kannst, ist die Trennung zwischen principal und StrSID komplett hinfaellig. Beide koennen equivalent benutzt werden. Noch'n Nachtrag: Warum _tmain wenn du ohnehin komplett in Unicode arbeiten willst? Es hilft dem Compiler ungemein, wenn du ihm erklaerst was du willst :zwinker: |
Re: Unicode Eingabe einlesen
Genau mit diesem Unicode Mischmasch und mit Zeichenketten unter C/C++ habe ich ja so meine Probleme, deswegen wollte ich mir das mal genauer angucken und endlich mal verstehen.
Zum Programm: Unicode ist in den Projektoptionen eingestellt, deswegen dachte ich, ich müsste es nicht noch mal im Code definieren. Zitat:
Zitat:
Delphi-Quellcode:
Nicht wirklich. :gruebel:
// wprintf(INFO);
// wprintf(QUERYINPUT); <--- warum die auskommentiert sind sollte klar sein Zitat:
Zitat:
|
Re: Unicode Eingabe einlesen
Zitat:
Zitat:
Zitat:
Zitat:
Spaeter habe ich gesehen, dass zumindest INFO oben schon deklariert war. Aber eben nicht in dem Beitrag den ich zitiert habe. Zitat:
Zitat:
|
Re: Unicode Eingabe einlesen
Zitat:
Zitat:
Zitat:
|
Re: Unicode Eingabe einlesen
Zitat:
Zitat:
Zitat:
|
Re: Unicode Eingabe einlesen
Zum letzten Punkt: Ich meinte wie main "aussehen" muss. Bei _tmain hast du ja gesagt es "gehöre" zu TCHAR. Aber wie sieht der Einsprungspunkt aus, wen ich WCHAR verwende? Oder hab eich da jetzt einfach nur was übersehen oder falsch verstanden?
|
Re: Unicode Eingabe einlesen
Ich glaube das war dann wmain. Muesstest du dir mal die Definition fuer _tmain anschauen.
|
Re: Unicode Eingabe einlesen
So. So sieht es bisher aus:
Code:
Allerdings kennt er die API-Funktion ConvertSidToStringSidW nicht, obwohl ich die Sddl.h eingebunden und die Advapi32.lib mit gelinkt wird. Benutzen tue ich das Visual Studio 2005.
#include "stdafx.h"
#include <windows.h> #include <Sddl.h> #define INFO _T("Ausgabe der SIDs zu einem Principal\n") #define QUERYINPUT _T("Principal (z.B. Benutzername): ") DWORD GetStrSID(LPCWSTR server, LPCWSTR principal, LPWSTR &StrSID) { // SID ermitteln und in lesbare Form umwandeln // in StrSID zurückgeben PSID Sid; DWORD cbSize = 0; if (LookupAccountNameW(NULL, principal, NULL, &cbSize, NULL, NULL, NULL)) { Sid = (PSID) new BYTE[256]; LookupAccountNameW(NULL, principal, Sid, &cbSize, NULL, NULL, NULL); //ConvertSidToStringSidW(Sid, StrSID); delete Sid; } return GetLastError(); } int wmain(int argc, _TCHAR* argv[]) { WCHAR principal[80], *StrSID = principal; DWORD LastError; wprintf(INFO); wprintf(QUERYINPUT); wscanf(L"%s", &principal); wprintf(L"%s\n", principal); LastError = GetStrSID(NULL, principal, StrSID); if (LastError == 0) { wprintf(L"%s", StrSID); } else { wprintf(L"%i", LastError); } getchar(); return 0; } Ich habe die Funktion erstmal auskommentiert, aber trotzdem kommt es noch zu einer AV beim Aufruf von if (LookupAccountNameW(NULL, principal, NULL, &cbSize, NULL, NULL, NULL)). |
Re: Unicode Eingabe einlesen
Es muss wscanf(L"%S", &principal); und nicht wscanf(L"%s", &principal); heißen also ein "%S" statt "%s".
Mit "%s" ließt man char* ein. Mit "%S" wchar_t* |
Re: Unicode Eingabe einlesen
Wenn ich das grosse S nehme, dann kommt in der Funktion GetStrSID nur Mist an.
Ich habe jetzt mal die standard Aufrufkonvention in den Projekteigenschaften von __cdecl auf __stdcall umgestellt, aber das hilft leider auch nicht. |
Re: Unicode Eingabe einlesen
Zitat:
Zitat:
Code:
in der sddl.h hattest du aber gesehen?
#if(_WIN32_WINNT >= 0x0500)
|
Re: Unicode Eingabe einlesen
Den Adressoperator hatte ich noch übersehen. Mit %S und ohne Adressoperator geht es jetzt. Und ich bekomme auch keine AV mehr. Allerdings ist cbSize immer null:
Code:
DWORD GetStrSID(LPCWSTR server, LPCWSTR principal, LPWSTR &StrSID)
{ // SID ermitteln und in lesbare Form umwandeln // in StrSID zurückgeben PSID Sid; DWORD cbSize = 0; LookupAccountNameW(NULL, principal, NULL, &cbSize, NULL, 0, NULL); if (cbSize > 0) { Sid = (PSID) new BYTE[256]; LookupAccountNameW(NULL, principal, Sid, &cbSize, NULL, 0, NULL); wprintf(L"%i", cbSize); //ConvertSidToStringSidW(Sid, StrSID); delete Sid; } return GetLastError(); } Zitat:
Mann ist das kompliziert. :roll: |
Re: Unicode Eingabe einlesen
Liste der Anhänge anzeigen (Anzahl: 1)
... bla bla bla ...
Code:
Den ersten Teil kannste weglassen wenn du die korrekte Zielplatform (mind. W2K waehlst). ConvertSidToStringSid, das steht auch in der Doku (PSDK) alloziert den String selber, was du gemacht hast, war also gelinde gesagt Mist.
#include <stdio.h>
#include <tchar.h> #include <Windows.h> #ifndef ConvertSidToStringSid #ifdef __cplusplus extern "C" { #endif BOOL WINAPI ConvertSidToStringSidA( IN PSID Sid, OUT LPSTR *StringSid ); BOOL WINAPI ConvertSidToStringSidW( IN PSID Sid, OUT LPWSTR *StringSid ); #ifdef UNICODE #define ConvertSidToStringSid ConvertSidToStringSidW #else #define ConvertSidToStringSid ConvertSidToStringSidA #endif // !UNICODE #ifdef __cplusplus }; #endif #endif // ConvertSidToStringSid #define INFO L"Ausgabe der SIDs zu einem Principal\n" #define QUERYINPUT L"Principal (z.B. Benutzername): " DWORD GetStrSID(LPCWSTR server, LPCWSTR principal, WCHAR StrSID[80]) { PSID Sid = NULL; DWORD cbSize = 0; if (LookupAccountNameW(NULL, principal, NULL, &cbSize, NULL, NULL, NULL)) { if(Sid = PSID(new BYTE[cbSize])) { LPWSTR lpwszTemp = NULL; if(LookupAccountNameW(NULL, principal, Sid, &cbSize, NULL, NULL, NULL)) { if(ConvertSidToStringSidW(Sid, &lpwszTemp)) { // Fill with zeros memset(StrSID, 0, sizeof(StrSID)); // Copy string into buffer memcpy(StrSID, lpwszTemp, sizeof(StrSID) - sizeof(WCHAR)); // Free the string allocated by ConvertSidToStringSidW LocalFree(HLOCAL(lpwszTemp)); SetLastError(ERROR_SUCCESS); } } delete Sid; } else { SetLastError(ERROR_NOT_ENOUGH_MEMORY); } } return GetLastError(); } int __cdecl _tmain(int argc, _TCHAR* argv[]) { WCHAR principal[80] = {0}; DWORD LastError; wprintf(INFO); wprintf(QUERYINPUT); wscanf(L"%S", principal); wprintf(L"%S\n", principal); if (ERROR_SUCCESS == (LastError = GetStrSID(NULL, principal, principal))) { wprintf(L"%s", principal); } else { wprintf(L"Error %d", LastError); } getchar(); return 0; } In einer Domaene funzt dein Ansatz logischerweise so nicht. Wer GetLastError() auswertet sollte im Erfolgsfall auch explizit den Erfolg signalisieren. "new BYTE[256]" war wohl Quark, wenn du offenbar zuvor die exakte Groesse zu ermitteln versuchtest. Also warum nicht auch diese benutzen? |
Re: Unicode Eingabe einlesen
Stoer dich nicht am _tmain, liegt an bestimmten Projekteinstellungen meines Testprojektes (hab's mit dem DDK getestet).
|
Re: Unicode Eingabe einlesen
Welche Zielplatform muss ich denn wie, wo einstellen, damit er ConvertSidToStringSidW kennt?
Ansonsten danke erstmal. Da ist ja nicht all zuviel von meinem Code übrig geblieben, da werde ich mich erstmal durchwühlen müssen. |
Re: Unicode Eingabe einlesen
Zitat:
Alternativ uebernimmst du den Teil zwischen "#ifndef ConvertSidToStringSid" und "#endif // ConvertSidToStringSid" in deinen Code. Selbst wenn es dann schon woanders deklariert wurde, wird das nicht stoeren und du brauchst Sddl.h nicht mehr explizit einbinden. Statt der ersten beiden Includes waere es bei dir dann wohl nur stdafx.h ... Zitat:
|
Re: Unicode Eingabe einlesen
Zitat:
Code:
Jetzt steht in principal wieder nur ein eckiges Kästchen drinne, anstatt der eingegebenen Zeichenkette. :wall:
int wmain(int argc, _CHAR* argv[])
{ WCHAR principal[80] = {0}; DWORD LastError; wprintf(INFO); wprintf(QUERYINPUT); wscanf(L"%S", principal); if (ERROR_SUCCESS == (LastError = GetStrSID(NULL, principal, principal))) { wprintf(L"%s", principal); } else { wprintf(L"Error %d", LastError); } getchar(); return 0; } PS: Ich bin hier in einer Domäne. Aber wenn ich einen lokalen Account angebe, sollte es doch funktionieren oder? PPS: Wo kann ich beim VS die Zielplattfiorm angegeben? Ich finde da nichts in den Projektoptionen. :gruebel: |
Re: Unicode Eingabe einlesen
Zitat:
Zitat:
Zitat:
Ich schaue nochmal ueber den Code und teste aus an einem lokalen Account. Paar Minuetchen. Muss ja wohl in GetStrSID() haengen. |
Re: Unicode Eingabe einlesen
Glaube ich nicht. Es hängt an der Eingabe, dass er da die Eingabe nicht richtig liest, warum auch immer.
Code:
Ich hatte auch schon WINNT=0x0500 bei den Präprozessiranweisungen hinzugefügt, das hat aber auch nicht geholfen. Und mit #define WINNT 0x0500 geht es auch nicht. Das kann doch einfach nicht so schwer sein. :wall:
#include "stdafx.h"
#include <windows.h> #define WINNT 0x0500 #define INFO L"Ausgabe der SIDs zu einem Principal\n" #define QUERYINPUT L"Principal (z.B. Benutzername): " DWORD GetStrSID(LPCWSTR server, LPCWSTR principal, WCHAR StrSID[80]) { PSID Sid = NULL; DWORD cbSize = 0; if (LookupAccountNameW(NULL, principal, NULL, &cbSize, NULL, NULL, NULL)) { if(Sid = PSID(new BYTE[cbSize])) { LPWSTR lpwszTemp = NULL; if(LookupAccountNameW(NULL, principal, Sid, &cbSize, NULL, NULL, NULL)) { if(ConvertSidToStringSidW(Sid, &lpwszTemp)) { // Fill with zeros memset(StrSID, 0, sizeof(StrSID)); // Copy string into buffer memcpy(StrSID, lpwszTemp, sizeof(StrSID) - sizeof(WCHAR)); // Free the string allocated by ConvertSidToStringSidW LocalFree(HLOCAL(lpwszTemp)); SetLastError(ERROR_SUCCESS); } wprintf(L"%i", cbSize); } delete Sid; } else { SetLastError(ERROR_NOT_ENOUGH_MEMORY); } } return GetLastError(); } int wmain(int argc, _TCHAR* argv[]) { WCHAR principal[80] = {0}; DWORD LastError; wprintf(INFO); wprintf(QUERYINPUT); wscanf(L"%S", principal); if (ERROR_SUCCESS == (LastError = GetStrSID(NULL, principal, principal))) { wprintf(L"%s", principal); } else { wprintf(L"Error %d", LastError); } getchar(); return 0; } |
Re: Unicode Eingabe einlesen
"#define _WIN32_WINNT 0x0500" (bzw. _WIN32_WINNT=0x0500)
Ich habe noch zwei subtile Dinge bei deinem Code uebersehen. 1. new fuer Arrays erfordert delete[], niemals delete! 2. new kann eine Exception werfen. Solltest du also danach noch im Zweifelsfall handeln. Uebrigens, wenn wir schon bei C++ sind, solltest du eventuell lieber I/O Streams benutzen und bei den Formatstrings sollte natuerlich die Puffergroesse Beachtung finden ... also 79 in unserem Fall. Bei mir liest er die Eingabe voellig korrekt. Also duerftest du nur wieder irgendwelche eigenen Aenderungen gemacht haben. Ich kapier nicht, wieso du nicht einfach meine Aenderungen 1:1 uebernimmst und dann als Ausgangspunkt nimmst. Aber ich mache ohnehin gerade noch ein paar Aenderungen. PSDK lesen hilft uebrigens ... die Funktionsaufrufe sind zT hanebuechen ... |
Re: Unicode Eingabe einlesen
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
|
Re: Unicode Eingabe einlesen
Siehe Anhang mit EXE-Datei. Bitte mal testen ob er einen Fehler bringt. Bei mir kommt leider immer Fehler 1332 (ERROR_NONE_MAPPED), weshalb ich nicht weiter als bis zum ersten LookupAccountName komme :(
|
Re: Unicode Eingabe einlesen
Liste der Anhänge anzeigen (Anzahl: 1)
Autsch. Der letzte Fehler ging auf mich - dank pitti platsch - auf den ich ungeprueft gehoert hatte. Es muss naemlich nicht %S (was bei printf Unicode und bei wprintf ANSI bedeutet), sondern %ws heissen. (%S ist sozusagen immer der "entgegengesetzte" Stringtyp)
Danach funzt der Input und der Rest. Auf die Spur dessen bin ich dann auch erst gekommen, nachdem ich mal ein Literal uebergeben habe. Siehe Anhang mit EXE und Source. Ausser der Behandlung der Exceptions welche von new() geworfen werden koennten, wird eigentlich alles gecheckt. |
Re: Unicode Eingabe einlesen
Puh jetzt geht es endlich. Mann war das eine schwere Geburt. :? Jetzt muss ich mir nur noch angucken, was da genau passiert, um es zu verstehen.
Allerdings verstehe ich nicht, warum du da solche Probleme hattest, ich dachte so was machst du Tag täglich. :gruebel: |
Re: Unicode Eingabe einlesen
Zitat:
Zitat:
Ein Teil der Probleme ergab sich allerdings daraus, daß ich den Fehler eben an einer anderen Stelle vermutet hatte (nämlich beim Lookup). Aber durch deinen Hinweis bzgl. der Eingabe habe ich mich dann auf den anderen Teil gestürzt und prompt den Fehler gefunden. Übrigens gibt's im Kernelmode auch relativ selten Eingabeaufforderungen ... soviel zum tagtäglichen ... :zwinker: |
Re: Unicode Eingabe einlesen
OK, ich versuche dass dann noch mal mit Streams hinzubekommen, damit es ein sauberes C++ wird. Und dann poste ich es nochmal hier.
Irgendwann muss ich das doch mit den Zeichenketten und C/C++ in den Kopf bekommen. :wall: |
Re: Unicode Eingabe einlesen
Ich versuche gerade die Ein- und Ausgabe mit Streams zu realisieren:
Code:
Die Ausgabe funktioniert, die Eingabe jedoch nicht:
cout << INFO << endl;
cout << QUERYINPUT << endl; cin >> principal; Zitat:
|
Re: Unicode Eingabe einlesen
Am besten schreibst du dir einen eigenen Operator dafür. Alternativ benutzt du gleich die STL std::string-Klasse für Ein/Ausgaben. Natürlich mit wchar_t spezialisiert.
|
Re: Unicode Eingabe einlesen
Zitat:
Zitat:
PS: Sollten wir uns auf den Delphi Tagen 2007 in Paderborn treffen oder sollte ich mal nach Island kommen, gebe ich dir einen aus. ;) |
Re: Unicode Eingabe einlesen
Zitat:
Zitat:
Ehrlich gesagt habe ich ueberlegt zu den diesjaehrigen Delphitagen mal zu kommen. |
Re: Unicode Eingabe einlesen
OK, dann belasse ich es dabei. Dann kann man das Thema jetzt als Abgeschlossen betrachten.
Und was die Delphitage angeht: Überleg nicht lange, sondern komm einfach. Nico habe ich schon per Mail gefragt, aber noch keine Antwort erhalten. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:23 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz