GetPrivateProfileString Zugriffsverletzung



  • Ich möchte eine Funktion schreiben, in der eine .ini Datei ausgelesen wird. Wenn die Datei nicht gefunden ist oder sonst noch was, soll eine Fehlermeldung ausgegeben werden.
    Damit ich das ganze nicht für jeden Datentyp machen muss, habe ich ein template erstellt. Das ganze sieht so aus:

    template<typename T>
    T readSettings(LPWSTR app, LPWSTR key, LPWSTR path, T init) {
    	if (!GetPrivateProfileString(app, key, NULL, init, 500, path)) {
    		MessageBox(NULL, _T("Inititalisierungsdatei ist beschädigt oder konnte nicht gefunden werden"), _T("ERROR"), MB_OK | MB_ICONERROR);
    	}
    	return 0;
    }
    

    Jetzt gibt der Debugger folgende Meldung aus:

    Eine Ausnahme (erste Chance) bei 0x7c80fa67 in Test.exe: 0xC0000005: Zugriffsverletzung beim Schreiben an Position 0x00417810.
    Unbehandelte Ausnahme bei 0x7c80fa67 in Test.exe: 0xC0000005: Zugriffsverletzung beim Schreiben an Position 0x00417810.
    

    Die Funktion wird so aufgerufen:

    LPWSTR title = _T("");
    readSettings<LPWSTR>(_T("init"),_T("title"),filepath, title);
    

    Die Variable filepath wird so erstellt:

    LPTSTR commandline = GetCommandLine();
    wchar_t buffer[MAX_PATH + 2];
    wcscpy_s(buffer,commandline);
    LPWSTR sFileName = wcsrchr(buffer,'\\') + 1;
    *sFileName = '\0';
    wcscat_s(buffer, _T("settings.ini"));
    LPWSTR filepath = buffer;
    

    Theoretisch sollte doch eigentlich alles stimmen. Aber das tut es leider nicht 😞



  • GetPrivateProfileString(app, key, NULL, init, 500, path)
    

    "init" ist ein Pointer auf einen Puffer. Du übergibst hier:

    LPWSTR title = _T("");
    readSettings<LPWSTR>(_T("init"),_T("title"),filepath, title);
    

    einen Pointer, der auf einen Leerstring zeigt (laut Google gibt _T einen String als Unicode-Version zurück). Also ist der Puffer zu klein und es kracht. Versuchs doch mal mit einem

    LPWSTR title[500]
    

    . Schließlich gibst du ja an, dass 500 Zeichen in den Puffer passen:

    GetPrivateProfileString(app, key, NULL, init, >>500<<, path
    

    Alle Angaben ohne Gewähr.



  • Danke, jetzt funktioniert das zwar, wenn ich das hier ausprobiere:

    wchar_t title[500];
    GetPrivateProfileString(_T("init"), _T("title"), NULL, title, 500, buffer);
    LPWSTR title2 = title;
    

    ist title2 null. Wie bekomme ich das hin, das der Wert aus title korrekt in title2 geschrieben wird?



  • Hab jetzt nochmal geguckt, und gesehen, dass es am Pfad liegt. Das Problem ist, das aus
    "C:\\Dokumente und Einstellungen\\Mein Name\\Eigene Dateien\\Visual Studio 2010\\Projects\\Freetype2\\Debug\\settings.ini"

    "C:\\Dokumente und Einstellungen\\Mein Name\\eigene dateien\\visual studio 2010\\Projects\\Freetype2\\Debug\\settings.ini"

    wird.
    Eigene Dateien und Visual Studio sind also klein geschrieben. Der Rest vom Pfad ist aber korrekt groß geschrieben. Wie schaff ich es, dass der Pfad komplett richtig groß geschrieben wird?

    EDIT: Hab zwar jetzt rausgefunden, dass es mit GetCurentDirectory viel einfach geht, aber der Pfad ist immernoch halb klein geschrieben und stimmt somit nicht.
    EDIT2: GetModuleFileName gibt auch den falschen Pfad aus.



  • Wenn ich das Programm per Hande starte(also im Ordner auf die .exe klicke) wird der Pfad korrekt angezeigt. Nur wenn ich aus Visual Studio 2010 aus das Programm starte ist der Pfad falsch. Das ist jetzt aber ein bisschen blöd. da ich mein Programm ja auch Debuggen möchte und nicht für jeden Release erstmal was ändern muss. Wie schaff ich es, dass auch Visual Studio den richtigen Pfad findet?



  • Windows interessiert sich nicht für Groß-/Kleinschreibung bei Pfäden, das wird es nicht sein.



  • Hmm irgendwie klappts jetzt. Keine Ahnung was ich gemacht habe.
    Eine Frage habe ich allerdings noch.
    Wie kann ich überprüfen welcher Datentyp T ist in diesem Fall:

    template<typename T>
    T readSettings(LPWSTR app, LPWSTR key, LPWSTR path, T init) {
    	wchar_t buffer[500];
    	if (!GetPrivateProfileStringW(app, key, NULL, buffer, sizeof(buffer), path)) {
    		MessageBox(NULL, _T("Inititalisierungsdatei ist beschädigt oder konnte nicht gefunden werden"), _T("ERROR"), MB_OK | MB_ICONERROR);
    		return 0;
    	}
    	return init;
    }
    

    Wenn ich die größe von T überprüfe, also ob T 1,2,4,8 Byte groß ist, kann wenn T = 1 Byte ist T ein char oder bool sein und wenn T = 4 ist, kann T int, float oder long sein. Geht es irgendwie genauer?



  • Nein, geht ohne Umwege nicht.

    Zu deinem vorherigen Problem:
    Beim starten aus der IDE wird die Anwendung nicht im Unterordner Release oder Debug ausgeführt, sondern in dem darüber.
    Die Datei müsste also hier liegen, wenn du aus der IDE starten willst:
    C:\\Dokumente und Einstellungen\\Mein Name\\Eigene Dateien\\Visual Studio 2010\\Projects\\Freetype2\\settings.ini



  • Der Pfad, aus dem sich Visual Studio die Daten holt ist

    C:\\Dokumente und Einstellungen\\Mein Name\\Eigene Dateien\\Visual Studio 2010\\Projects\\Freetype2\\Freetype2\\
    

    Dennoch wird die .exe im Debug Ordner ausgeführt.
    Mit dem Pfad klappt ja jetzt alles, und das lesen habe ich jetzt konventioneller und stabiler gemacht. Waren zwar 4 mal so viel Zeilen Code, aber dafür siehts jetzt genau so aus, wie ich es wollte.


Anmelden zum Antworten