Alexander (HH): INI-Datei verschieben

Moin Moin!

Nein, ich weiß, wie man Dateien verschiebt. ;-)

Ich bzw. wir müssen uns mit einer Entwicklungsumgebung + Runtime herumschlagen, die einen Großteil ihrer Einstellungen in einer zentralen INI-Datei ablegt und sie dort natürlich auch wieder sucht. Blöderweise erwartet dieses System die INI-Datei im Windows-Verzeichnis und nicht in dem Verzeichnis, in dem wir unsere Projekte verwalten. Zu jedem Projekt gehören größere Änderungen an der INI-Datei, es wäre also extrem sinnvoll und nützlich, diese Datei zusammen mit dem Rest des Projekts unter eine Versionskontrolle zu stellen.

Letztlich ruft die Anwendung über ein paar Abstraktionslayer die Windows-API-Funktionen GetPrivateProfileString(), GetPrivateProfileInt() und WritePrivateProfileString() auf, das läßt sich anhand der Strings in den EXE-Dateien nachvollziehen. Der jeweils letzte Parameter, lpFileName, ist entweder nur der reine Dateiname "blafasel.ini", oder aber einer der Wrapper bastelt noch den Namen des Windows-Verzeichnisses vor "blafasel.ini", das kann ich im Moment nicht sehen. Egal wie, in beiden Fällen sucht Windows die INI-Datei ausschließlich im Windows-Verzeichnis, und da gehört sie wenigstens auf den Entwickler-Systemen nicht hin.

Ich suche also irgendeinen Kniff, wie ich Windows oder die Anwendung dazu bringe, die INI-Datei in einem Verzeichnis meiner Wahl zu suchen. Das in Windows implementierte IniFileMapping klingt zwar schön, aber murkst die INI-Dateien nur in die Registry-Müllhalde, wo sie noch schlechter kontrollierbar sind.

Die Original-EXEs können wir nicht ändern, Zugriff auf Quelltexte gibt's schon mal gar nicht, und eine Spezialversion der Umgebung wird man uns nicht bauen.

Bleibt also eigentlich nur noch, die Programme zur Laufzeit auszutricksen. Man müßte die drei Funktionen auf eigene Funktionen umbiegen, so ähnlich wie das iwatch aus dem c't-Artikel Wachtmeister macht, um den Original-Funktionen den "richtigen" Verzeichnispfad mitzugeben.

Ein Aufruf à la "LOADER.EXE /ini=D:\svnhome\project42\blafasel.ini DEVELOP.EXE" bzw. "LOADER.EXE /ini=D:\svnhome\project42\blafasel.ini RUNTIME.EXE project42" wäre für uns Entwickler überhaupt kein Problem, sondern quasi die Ideallösung, mit der wir die Projekte sauber voneinander trennen könnten.

Gibt's was fertiges dafür? Irgendwelche Hinweise? Alternative Ideen?

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
  1. Hallo,

    Nein, ich weiß, wie man Dateien verschiebt. ;-)

    na da bin ich ja beruhigt!

    Ich bzw. wir müssen uns mit einer Entwicklungsumgebung + Runtime herumschlagen, die einen Großteil ihrer Einstellungen in einer zentralen INI-Datei ablegt und sie dort natürlich auch wieder sucht.

    Das ist fein - ist zumindest schonmal besser als die vielen Programme, die ihre Einstellungen irgendwo in der Registry ablegen.

    Blöderweise erwartet dieses System die INI-Datei im Windows-Verzeichnis und nicht in dem Verzeichnis, in dem wir unsere Projekte verwalten. [...]
    Letztlich ruft die Anwendung über ein paar Abstraktionslayer die Windows-API-Funktionen GetPrivateProfileString(), GetPrivateProfileInt() und WritePrivateProfileString() auf, das läßt sich anhand der Strings in den EXE-Dateien nachvollziehen.

    Die von dir verlinkte Beschreibung von MS ist unvollständig: Anders als dort angegeben suchen diese Funktionen (zumindest bis Windows XP, für Vista oder 7 keine Garantie) die Datei zuerst im Verzeichnis der Applikation (also das Verzeichnis, in dem die EXE-Datei liegt), dann im Windows-Verzeichnis. Oder halt exakt da, wo's der Programmierer vorgibt, wenn ein Pfad angegeben wird.

    Der jeweils letzte Parameter, lpFileName, ist entweder nur der reine Dateiname "blafasel.ini", oder aber einer der Wrapper bastelt noch den Namen des Windows-Verzeichnisses vor "blafasel.ini", das kann ich im Moment nicht sehen.

    Das wäre eigentlich unsinnig, aber was heißt das schon ...

    Egal wie, in beiden Fällen sucht Windows die INI-Datei ausschließlich im Windows-Verzeichnis, und da gehört sie wenigstens auf den Entwickler-Systemen nicht hin.

    Da gehört sie IMHO *grundsätzlich* nicht hin. Ist das Programmverzeichnis für dein Projekt keine gangbare Alternative? Denn da sollte sie als erstes gefunden werden.

    Ich suche also irgendeinen Kniff, wie ich Windows oder die Anwendung dazu bringe, die INI-Datei in einem Verzeichnis meiner Wahl zu suchen.

    Nicht ohne Änderung der Anwendung. Selbst wenn man der Anwendung ein anderes Arbeitsverzeichnis zuweist, sucht sie ihre INI-Dateien immer noch im Programmverzeichnis.

    Das in Windows implementierte IniFileMapping klingt zwar schön, aber murkst die INI-Dateien nur in die Registry-Müllhalde, wo sie noch schlechter kontrollierbar sind.

    ACK.

    Bleibt also eigentlich nur noch, die Programme zur Laufzeit auszutricksen. Man müßte die drei Funktionen auf eigene Funktionen umbiegen, so ähnlich wie das iwatch aus dem c't-Artikel Wachtmeister macht, um den Original-Funktionen den "richtigen" Verzeichnispfad mitzugeben.

    Puh, das ist dann im Prinzip die gleiche Technik, als wenn ein Debugger ein Programm unter seiner Kontrolle laufen lässt und dessen Code im Arbeitsspeicher beliebig manipulieren kann. Das wird dann richtig fies.

    Gibt's was fertiges dafür? Irgendwelche Hinweise? Alternative Ideen?

    Leider nein. Das sysinternals-Tool FileMon kann zwar Zugriffe beliebiger Prozesse auf das Filesystem überwachen und protokollieren, aber AFAIK nicht eingreifen.
    Was waren das noch für Zeiten, als man einfach den DOS-Interrupt 21h abgefangen und die Funktionsnummern und Parameter einfach abgefragt und umgebogen hat ...

    Ciao,
     Martin

    --
    Besteht ein Personalrat aus nur einer Person, erübrigt sich die Trennung nach Geschlechtern.
      (aus einer Info des deutschen Lehrerverbands Hessen)
    1. Moin Moin!

      Hallo,

      Nein, ich weiß, wie man Dateien verschiebt. ;-)

      na da bin ich ja beruhigt!

      Ich bzw. wir müssen uns mit einer Entwicklungsumgebung + Runtime herumschlagen, die einen Großteil ihrer Einstellungen in einer zentralen INI-Datei ablegt und sie dort natürlich auch wieder sucht.

      Das ist fein - ist zumindest schonmal besser als die vielen Programme, die ihre Einstellungen irgendwo in der Registry ablegen.

      Ja, finde ich auch. Nur sieht die INI-Datei im Moment (bevor ich den Müll mal aufräume) ähnlich übersichtlich aus wie ein Binärdump der Registry. Naja, das ist eine andere Baustelle.

      Blöderweise erwartet dieses System die INI-Datei im Windows-Verzeichnis und nicht in dem Verzeichnis, in dem wir unsere Projekte verwalten. [...]
      Letztlich ruft die Anwendung über ein paar Abstraktionslayer die Windows-API-Funktionen GetPrivateProfileString(), GetPrivateProfileInt() und WritePrivateProfileString() auf, das läßt sich anhand der Strings in den EXE-Dateien nachvollziehen.

      Die von dir verlinkte Beschreibung von MS ist unvollständig: Anders als dort angegeben suchen diese Funktionen (zumindest bis Windows XP, für Vista oder 7 keine Garantie) die Datei zuerst im Verzeichnis der Applikation (also das Verzeichnis, in dem die EXE-Datei liegt), dann im Windows-Verzeichnis.

      Hmmm, genau das hatte ich auch im Kopf, aber das ist das Suchverhalten für DLLs (LoadLibrary()), nicht für INIs.

      Und ich hab der Doku auch nicht geglaubt, aber eine blafasel.ini direkt neben meiner Test.EXE wird zugunsten der blafasel.ini im Windows-Verzeichnis ignoriert, wenn ich GetPrivateProfileString(....,"blafasel.ini") aufrufe, sowohl unter XP SP3 als auch unter W2K SP4. Die INI-Datei neben der Test.EXE wird auch dann ignoriert, wenn keine blafasel.ini im Windows-Verzeichnis liegt. GetPrivateProfileString() liefert dann den Wert des Default-Parameters zurück.

      Test.c:

        
      #include <stdio.h>  
      #include <stdlib.h>  
      #include <windows.h>  
        
      int main(int argc, char ** argv)  
      {  
      	char buf[1024];  
        
      	GetPrivateProfileString("hallo","welt","*DEFAULT*",buf,sizeof(buf),"blafasel.ini");  
      	puts(buf);  
      	return 0;  
      }  
      
      

      blafasel.ini:

      [hallo]
      welt=moin

      Oder halt exakt da, wo's der Programmierer vorgibt, wenn ein Pfad angegeben wird.

      Ja, genau.

      Der jeweils letzte Parameter, lpFileName, ist entweder nur der reine Dateiname "blafasel.ini", oder aber einer der Wrapper bastelt noch den Namen des Windows-Verzeichnisses vor "blafasel.ini", das kann ich im Moment nicht sehen.

      Das wäre eigentlich unsinnig, aber was heißt das schon ...

      Das heißt, dass der Code-Sklave die Doku nicht zuende gelesen hat oder genug Erfahrung mit MS hat, dem dokumentierten Default-Verhalten nicht weiter zu trauen, als er seinen Rechner werfen kann.

      Egal wie, in beiden Fällen sucht Windows die INI-Datei ausschließlich im Windows-Verzeichnis, und da gehört sie wenigstens auf den Entwickler-Systemen nicht hin.

      Da gehört sie IMHO *grundsätzlich* nicht hin. Ist das Programmverzeichnis für dein Projekt keine gangbare Alternative?

      Doch, genau da soll sie hin. Deswegen ja dieser Thread.

      Denn da sollte sie als erstes gefunden werden.

      Nur wenn die INI eine DLL wäre und per LoadLibrary() geladen würde.

      Ich suche also irgendeinen Kniff, wie ich Windows oder die Anwendung dazu bringe, die INI-Datei in einem Verzeichnis meiner Wahl zu suchen.

      Nicht ohne Änderung der Anwendung. Selbst wenn man der Anwendung ein anderes Arbeitsverzeichnis zuweist, sucht sie ihre INI-Dateien immer noch im Programmverzeichnis.

      Eben. Ich hab keinen Quelltext, ich kann und vor allem DARF die Executables nicht patchen, also bleibt mir nur noch, die Programme jedes Mal wieder im Speicher zu patchen.

      Das in Windows implementierte IniFileMapping klingt zwar schön, aber murkst die INI-Dateien nur in die Registry-Müllhalde, wo sie noch schlechter kontrollierbar sind.

      ACK.

      Bleibt also eigentlich nur noch, die Programme zur Laufzeit auszutricksen. Man müßte die drei Funktionen auf eigene Funktionen umbiegen, so ähnlich wie das iwatch aus dem c't-Artikel Wachtmeister macht, um den Original-Funktionen den "richtigen" Verzeichnispfad mitzugeben.

      Puh, das ist dann im Prinzip die gleiche Technik, als wenn ein Debugger ein Programm unter seiner Kontrolle laufen lässt und dessen Code im Arbeitsspeicher beliebig manipulieren kann. Das wird dann richtig fies.

      Ja. Ich hab mir gerade mal die Quelltexte ausgepackt. VC4 mit handgemachten Extras. *schauder*

      Gibt's was fertiges dafür? Irgendwelche Hinweise? Alternative Ideen?

      Leider nein. Das sysinternals-Tool FileMon kann zwar Zugriffe beliebiger Prozesse auf das Filesystem überwachen und protokollieren, aber AFAIK nicht eingreifen.

      Richtig. Und laut Regmon fragt weder Entwicklungsumgebung noch Runtime die Registry ab, wo die INI-Datei denn liegen soll. *grummel*

      Was waren das noch für Zeiten, als man einfach den DOS-Interrupt 21h abgefangen und die Funktionsnummern und Parameter einfach abgefragt und umgebogen hat ...

      Ja, und sich dann irgendwann gewundert hat, warum die Kiste abstürzt, nur weil der blöde Interupt irgendwo ins mittlerweile überschriebene Nirvana zeigt ... ;-)

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
      1. Hallo,

        Die von dir verlinkte Beschreibung von MS ist unvollständig: Anders als dort angegeben suchen diese Funktionen (zumindest bis Windows XP, für Vista oder 7 keine Garantie) die Datei zuerst im Verzeichnis der Applikation (also das Verzeichnis, in dem die EXE-Datei liegt), dann im Windows-Verzeichnis.
        Hmmm, genau das hatte ich auch im Kopf, aber das ist das Suchverhalten für DLLs (LoadLibrary()), nicht für INIs.

        ich dachte für beides ... aber du hast mich verunsichert. Ich habe jetzt tatsächlich mal in die Quellcodes meiner Standardmodule gesehen, die ich seit Jahren quasi unverändert benutze: Ich frage über GetModuleFileName() den Namen der EXE-Datei ab, schneide die drei Zeichen am Schluss ab und ergänze "ini" oder "cfg".
        Sorry: Mein Irrtum lag darin, dass ich überzeugt war, GetModuleFileName() gäbe mir nur den Namen - tatsächlich liefert mir das aber den kompletten Pfad. Dann ist logisch, dass ich auch die INI-Datei im Programmverzeichnis finde.

        Oder halt exakt da, wo's der Programmierer vorgibt, wenn ein Pfad angegeben wird.
        Ja, genau.

        So wie bei mir - nur dass mir das nicht mehr bewusst war.

        Das sysinternals-Tool FileMon kann zwar Zugriffe beliebiger Prozesse auf das Filesystem überwachen und protokollieren, aber AFAIK nicht eingreifen.
        Richtig. Und laut Regmon fragt weder Entwicklungsumgebung noch Runtime die Registry ab, wo die INI-Datei denn liegen soll. *grummel*

        Das wär ja dann auch zu einfach gewesen.

        Was waren das noch für Zeiten, als man einfach den DOS-Interrupt 21h abgefangen und die Funktionsnummern und Parameter einfach abgefragt und umgebogen hat ...
        Ja, und sich dann irgendwann gewundert hat, warum die Kiste abstürzt, nur weil der blöde Interupt irgendwo ins mittlerweile überschriebene Nirvana zeigt ... ;-)

        Das auch gelegentlich. Meist hat es aber ganz gut funktioniert, weil die Systeme und Zusammenhänge noch überschaubar waren.

        Ciao,
         Martin

        --
        Verliebt:    Er spricht, sie lauscht.
        Verlobt:     Sie spricht, er lauscht.
        Verheiratet: Beide sprechen, und die Nachbarn lauschen.
  2. Hallo Alexander

    … Alternative Ideen?

    Vielleicht gäbe es eine Möglichkeit, die Entwicklungsumgebung nicht direkt, sondern per Script zu starten, welches vor dem Start dieser, die INI-Datei mit der aus der Projektverwaltung überschreibt und als letzte Aktion diese wieder dort sichert?
    Dürfte natürlich knallen, wenn an mehreren Projekten gleichzeitig gearbeitet wird.
    Das könnte aber durch dieses Script auch ausgeschlossen werden.

    Auf Wiederlesen
    Detlef

    --
    - Wissen ist gut
    - Können ist besser
    - aber das Beste und Interessanteste ist der Weg dahin!
    1. Moin Moin!

      Hallo Alexander

      … Alternative Ideen?

      Vielleicht gäbe es eine Möglichkeit, die Entwicklungsumgebung nicht direkt, sondern per Script zu starten, welches vor dem Start dieser, die INI-Datei mit der aus der Projektverwaltung überschreibt und als letzte Aktion diese wieder dort sichert?

      Hmmm, das ist nicht sonderlich stabil, weil es dann wieder zwei Dateiversionen gibt, an denen die Kollegen herumfummeln können, und mit tödlicher Sicherheit immer die falsche erwischen.

      Vor allem ist die Idee, pro Projekt eine INI-Datei zu haben und nur für die Server, auf denen später die Runtime läuft, die diversen einzelnen INIs zu einer großen INI-Datei zusammenzubauen.

      Dürfte natürlich knallen, wenn an mehreren Projekten gleichzeitig gearbeitet wird.

      Das kommt durchaus vor.

      Das könnte aber durch dieses Script auch ausgeschlossen werden.

      Nö, das muß weiterhin funktionieren.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
  3. Tach,

    Ich suche also irgendeinen Kniff, wie ich Windows oder die Anwendung dazu bringe, die INI-Datei in einem Verzeichnis meiner Wahl zu suchen.

    wie wäre es mit einem Hardlink?

    mfg
    Woodfighter

    1. Moin Moin!

      Ich suche also irgendeinen Kniff, wie ich Windows oder die Anwendung dazu bringe, die INI-Datei in einem Verzeichnis meiner Wahl zu suchen.

      wie wäre es mit einem Hardlink?

      Das wäre zumindest im ersten Schritt für eine globale INI-Datei für alle Projekte brauchbar. Schade nur, dass Windows und die Projektverzeichnisse auf zwei verschiedenen Partitionen liegen. Gut, letztere kann man verschieben, aber schön ist das auch nicht.

      Und wenn irgendein Programm die Datei nicht öffnet und überschreibt, sondern stattdessen löscht und neu anlegt, bricht der Hardlink auseinander und ich habe zwei unabhängige Dateien.

      Wenn c:\winnt\blafasel.ini nun ein Symlink wäre ... -- leider kann Windows dass nur für Verzeichnisse.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".