Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Windows - Ricavare il percorso del file eseguibile
Forum - Windows - Ricavare il percorso del file eseguibile

Pagine: [ 1 2 ] Precedente | Prossimo
Avatar
()
Newbie


Messaggi:
Iscritto:

Segnala al moderatore
Postato alle 1:00
Giovedì, 01/01/1970
Visto che la mia richiesta precedente ha fruttato consigli che mi sono stati e mi sono preziosi, ci riprovo su un tema simile ma diverso: come posso ricavare il percorso completo del file eseguibile che contiene il programma in esecuzione?

Ho provato diverse soluzioni, ma nessuna risulta affidabile sempre. La mia intenzione sarebbe poter effettuare l'operazione nell'immediatezza del lancio del programma, in ambienti da Windows XP a Windows 8.

Prima soluzione: GetCurrentDirectory().
Inizialmente mi sembrava un'ottima soluzione, perché pareva fornire il percorso alla cartella che contiene il file eseguibile. Problema: se il programma viene lanciato con il drag and drop d'un file sull'icona del programma, restituisce il percorso del file trascinato, non del file del programma! Che seccatura!

Seconda soluzione: GetModuleFileName().
Anche questo sembrava non essere male, perché restituisce il percorso del file eseguibile, completato dal nome del file stesso. Apparentemente basterebbe rimuovere il nome del file eseguibile per avere il percorso della cartella che lo contiene (e non è difficile). Per qualche ragione, però, la funzione dà risultati differenti con diversi sistemi operativi (e non riesco a cogliere la logica che c'è sotto ai vari meccanismi).

Può essere che, nonostante i numerosi test, io continui a sbagliare qualcosa. Può anche essere che la strada da seguire non sia nessuna delle due che ho provato. Qualcuno vuole aiutarmi?

Ultima modifica effettuata da il 11/11/2014 alle 1:16
PM Quote
Avatar
nessuno (Normal User)
Guru^2


Messaggi: 6402
Iscritto: 03/01/2010

Segnala al moderatore
Postato alle 22:27
Lunedì, 10/11/2014
Ma con quale linguaggio?

Testo quotato

Per qualche ragione, però, la funzione dà risultati differenti con diversi sistemi operativi



Con precisione cosa succede?

Ultima modifica effettuata da nessuno il 10/11/2014 alle 22:36


Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti ( uno dei padri fondatori del moderno Calcolo delle probabilità ) chiamava il gioco del Lotto Tassa sulla stupidità.
PM Quote
Avatar
()
Newbie


Messaggi:
Iscritto:

Segnala al moderatore
Postato alle 1:42
Martedì, 11/11/2014
Il linguaggio che uso è il C/C++, interagendo con le API di Win32.

Alla domanda "con precisione cosa succede" mi resta difficile dare una risposta chiara, perché ho fatto talmente tante di quelle prove da aver creato nella mia testa un'insalata di possibilità che mi confonde alla grande.

Diciamo che ho un programmino ormai in stato avanzato di sviluppo che nelle intenzioni dovrebbe creare una cartella di file "di supporto" nella stessa cartella ove si trova l'eseguibile. Nella cartella "di supporto" si trovano un file di impostazioni e una serie di file di immagine che dovrebbero essere precaricati al lancio del programma. Il file di impostazioni dovrebbe essere inoltre aggiornato alla chiusura del programma. Se il file delle impostazioni è inaccessibile, al lancio vengono usate le impostazioni predefinite, mentre in chiusura viene inviato all'utente un semplice messaggio di notifica che avverte che le preferenze non sono state memorizzate.

Le cose funzionano bene su Windows 7 e 8, mentre in XP la cartella dei file di impostazione non viene trovata. E' come se qualcosa impedisse al programma di ricavare il percorso d'accesso, oppure come se l'accesso non fosse possibile anche in presenza del percorso corretto.

Tra le ipotesi che mi son venute in mente c'è anche quella che il problema non dipenda dal mio programma ma dalle credenziali d'accesso al percorso "incriminato": potrebbe essere che il sistema impedisca di accedere a certe cartelle per questioni legate a qualche opzione di protezione? (uso spesso il programma su computer che non sono di mia proprietà "armati" di dosi industriali di antivirus e software di protezione di varia natura) E se così fosse, come mai solo con XP?

Ah, il problema pare essere più frequente quando pongo l'eseguibile nella cartella radice (root directory) di un disco, tanto che si tratti del disco di sistema, quanto di un altro disco interno o di un volume rimovibile. Il casino è che a volte ottengo comportamenti apparentemente contraddittori dai quali non riesco a trarre una regola generale. Ho realizzato anche una versione di prova del programma che visualizza sotto forma testuale i percorsi con semplici MessageBox() inserite in punti strategici, e tutto sembra incredibilmente a posto (eppure il problema continua a presentarsi). Sono, come minimo, MOLTO confuso.

Dato che il file eseguibile si chiama "St'abbort'.exe" e ipotizzando che sia collocato nella cartella radice del volume "C", il percorso del programma così come viene "letto" è "C:\" e quello della cartella di supporto "C:\St'abbort' - File di supporto". Posto che il programma si trovasse in una sottocartella "Software personali" in un volume "E", i percorsi finirebbero per essere rispettivamente "E:\Software personali" e "E:\Software personali\St'abbort' - File di supporto". Non riesco a trovare niente di strano in nessuno dei due casi...

In qualche modo il trattamento del file system è diverso in XP rispetto a 7 e 8?

Per ogni altro verso il mio programma funziona alla perfezione. Volendo fare il figo m'azzarderei a definirlo "un gioiellino" (secondo i miei standard da amatore).

EDIT: dimenticavo... per peggiorare la confusione, ho un computer con XP mio personale sul quale tutto funziona liscio come l'olio... è assurdo!

Ultima modifica effettuata da il 11/11/2014 alle 1:48
PM Quote
Avatar
()
Newbie


Messaggi:
Iscritto:

Segnala al moderatore
Postato alle 1:55
Martedì, 11/11/2014
Il copia-e-incolla del codice sorgente dal quale credo nasca il problema è questo:

Codice sorgente - presumibilmente Windows

  1. ////////////////////////////////////////////////////////////////////////////////
  2. // Restituisce in pBuffer il puntatore ad uno spazio di memoria allocato      //
  3. // dinamicamente che contiene il percorso completo della cartella nella quale //
  4. // si trova il file eseguibile del programma abbinato ad hndIstanza.          //
  5. // La memoria dinamica puntata da pBuffer DEVE essere liberata per mezzo di   //
  6. // delete[].                                                                  //
  7. ////////////////////////////////////////////////////////////////////////////////
  8.  
  9. BOOL RicavaPercorsoProgramma( HINSTANCE hndIstanza, LPSTR *pBuffer ) {
  10.     try {
  11.         char *buff = new char[8*MAX_PATH];
  12.         DWORD l = GetModuleFileName( hndIstanza, buff, 8*MAX_PATH );
  13.  
  14.         l = EliminaUltimaPartePercorso( buff, l );
  15.         if( l>1 && buff[l-1]==':' ) { buff[l]='\\'; buff[++l]='\0'; }
  16.  
  17.         if( l >= 0 ) {
  18.             delete[] buff;
  19.             buff = new char[l+1];
  20.             l = GetModuleFileName( hndIstanza, buff, l+1 );
  21.         }
  22.  
  23.         *pBuffer = buff;
  24.  
  25.         return TRUE;
  26.     } catch( ... ) {
  27.         return FALSE;
  28.     }
  29. }
  30.  
  31.  
  32. ////////////////////////////////////////////////////////////////////////////////
  33. // Alloca dinamicamente una stringa nella quale vengono inseriti nell'ordine: //
  34. //     1. il percorso indicato da percBase                                    //
  35. //     2. un carattere '\\'                                                   //
  36. //     3. il nome del file indicato da "nomeAgg"                              //
  37. // Il parametro percBase DEVE riguardare una stringa C valida e non vuota.    //
  38. // E' compito del chiamante deallocare la stringa restituita quando non piu'  //
  39. // necessaria.                                                                //
  40. ////////////////////////////////////////////////////////////////////////////////
  41.  
  42. char *ComponiPercorso( const char *percBase, const char *nomeAgg ) {
  43.     const char *sep[] = { "", "\\" };
  44.  
  45.     try {
  46.         int lPercBase = lstrlen( percBase );
  47.         int lNomeAgg  = lstrlen( nomeAgg );
  48.         int lSep      = lstrlen( sep[lPercBase>3] );
  49.         int lPerc = lPercBase + lSep + lNomeAgg;
  50.         char *perc = new char[lPerc+1];
  51.         wsprintf( perc, "%s%s%s", percBase, sep[lPercBase>3], nomeAgg );
  52.         return perc;
  53.     } catch( ... ) {
  54.         return NULL;
  55.     }
  56. }
  57.  
  58.  
  59. ////////////////////////////////////////////////////////////////////////////////
  60. // Dato un percorso (es. C:\Cartella\file.txt) ne elimina l'ultima parte. Il  //
  61. // percorso assume quindi l'aspetto C:\Cartella.                              //
  62. // Il parametro "pc" sta per [p]ercorso [c]ompleto.                           //
  63. // Il parametro "lp" sta per [l]unghezza [p]ercorso.                          //
  64. // Restituisce la lunghezza del percorso risultante.                          //
  65. ////////////////////////////////////////////////////////////////////////////////
  66.  
  67. DWORD EliminaUltimaPartePercorso( char *pc, DWORD lp ) {
  68.     for( --lp; pc[lp]!='\\' && pc[lp]!='/' && lp>=0; --lp )
  69.         pc[lp] = '\0';
  70.     return lstrlen( pc );
  71. }


Ultima modifica effettuata da il 11/11/2014 alle 1:56
PM Quote
Avatar
()
Newbie


Messaggi:
Iscritto:

Segnala al moderatore
Postato alle 10:11
Martedì, 11/11/2014
Questa mattina mi son svegliato e, come per incanto, nella nebbia del dormiveglia ho avuto un' "illuminazione"! Non so spiegarmelo e so che ha dell'incredibile, però è così. Credo che aver riordinato le idee per spiegarle su questo forum sia stato fondamentale per "mettere in moto" i neuroni, per cui parte del merito è comunque vostro (ringrazio Nessuno per l'aiuto, anche se può sembrare che non ci sia stato nessun aiuto).

Comunque sia, alzatomi in fretta e furia, ho provato queste modifiche:

Codice sorgente - presumibilmente Windows

  1. ////////////////////////////////////////////////////////////////////////////////
  2. // Restituisce in pBuffer il puntatore ad uno spazio di memoria allocato      //
  3. // dinamicamente che contiene il percorso completo della cartella nella quale //
  4. // si trova il file eseguibile del programma abbinato ad hndIstanza.          //
  5. // La memoria dinamica puntata da pBuffer DEVE essere liberata per mezzo di   //
  6. // delete[].                                                                  //
  7. ////////////////////////////////////////////////////////////////////////////////
  8.  
  9. BOOL RicavaPercorsoProgramma( HINSTANCE hndIstanza, LPSTR *pBuffer ) {
  10.     try {
  11.         char *buff = new char[8*MAX_PATH];
  12.         DWORD l = GetModuleFileName( hndIstanza, buff, 8*MAX_PATH );
  13.  
  14.         l = EliminaUltimaPartePercorso( buff, l );
  15.         if( l>1 && buff[l-1]==':' ) { buff[l]='\\'; buff[++l]='\0'; }
  16.  
  17.         if( l >= 0 ) {
  18.             delete[] buff;
  19.             buff = new char[l+1];
  20.             l = GetModuleFileName( hndIstanza, buff, l+1 );
  21.         }
  22.  
  23.         *pBuffer = buff;
  24.  
  25.         return TRUE;
  26.     } catch( ... ) {
  27.         return FALSE;
  28.     }
  29. }
  30.  
  31.  
  32. ////////////////////////////////////////////////////////////////////////////////
  33. // Alloca dinamicamente una stringa nella quale vengono inseriti nell'ordine: //
  34. //     1. il percorso indicato da percBase                                    //
  35. //     2. un carattere '\\'                                                   //
  36. //     3. il nome del file indicato da "nomeAgg"                              //
  37. // Il parametro percBase DEVE riguardare una stringa C valida e non vuota.    //
  38. // E' compito del chiamante deallocare la stringa restituita quando non piu'  //
  39. // necessaria.                                                                //
  40. ////////////////////////////////////////////////////////////////////////////////
  41.  
  42. char *ComponiPercorso( const char *percBase, const char *nomeAgg ) {
  43.     try {
  44.         int lPercBase = lstrlen( percBase );
  45.         int lNomeAgg = lstrlen( nomeAgg );
  46.  
  47.         // determina quale separatore usare
  48.         const char *seps[] = { "", "\\" };
  49.         const char *sep = seps[lPercBase>3];
  50.         int lSep = lstrlen( sep );
  51.  
  52.         // determina la lunghezza del percorso in uscita
  53.         int lPerc = lPercBase + lSep + lNomeAgg;
  54.  
  55.         char *perc = new char[lPerc+1];
  56.  
  57.         wsprintf( perc, "%s%s%s", percBase, sep, nomeAgg );
  58.  
  59.         return perc;
  60.     } catch( ... ) {
  61.         return NULL;
  62.     }
  63. }
  64.  
  65.  
  66. ////////////////////////////////////////////////////////////////////////////////
  67. // Dato un percorso (es. C:\Cartella\file.txt) ne elimina l'ultima parte. Il  //
  68. // percorso assume quindi l'aspetto C:\Cartella.                              //
  69. // Il parametro "pc" sta per [p]ercorso [c]ompleto.                           //
  70. // Il parametro "lp" sta per [l]unghezza [p]ercorso.                          //
  71. // Restituisce la lunghezza del percorso risultante.                          //
  72. ////////////////////////////////////////////////////////////////////////////////
  73.  
  74. DWORD EliminaUltimaPartePercorso( char *pc, DWORD lp ) {
  75.     for( --lp; pc[lp]!='\\' && pc[lp]!='/' && lp>=0; --lp )
  76.         pc[lp] = '\0';
  77.  
  78.     // se il percorso "tagliato" termina con un carattere
  79.     // '\\', elimina l'ultimo carattere del percorso
  80.     if( pc[lp] == '\\' || pc[lp] == '/' )
  81.         pc[lp] = '\0';
  82.     else --lp;
  83.  
  84.     return lp;
  85. }



Ora pare che tutto funzioni, ma non ho a disposizione i molti computer che uso al lavoro, per cui ora copio l'eseguibile sulla mia fedele USB-Stick e domani testo il programma nelle classi, con Windows XP e Windows 8 negli ambienti di rete maniacalmente protetti della scuola. Sono fiducioso!

Ultima modifica effettuata da il 11/11/2014 alle 10:25
PM Quote
Avatar
nessuno (Normal User)
Guru^2


Messaggi: 6402
Iscritto: 03/01/2010

Segnala al moderatore
Postato alle 10:30
Martedì, 11/11/2014
Scusa ma non ho avuto modo di controllare le differenze ... cosa hai fatto per correggere?


Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti ( uno dei padri fondatori del moderno Calcolo delle probabilità ) chiamava il gioco del Lotto Tassa sulla stupidità.
PM Quote
Avatar
()
Newbie


Messaggi:
Iscritto:

Segnala al moderatore
Postato alle 11:10
Martedì, 11/11/2014
A parte alcune inezie formali, per un errore cretino in EliminaUltimaPartePercorso() in certe situazioni veniva lasciato un carattere '\\' di troppo in fondo al percorso. In conseguenza, quando si costruivano i percorsi alla cartella e ai file di supporto risultava un carattere '\\' "erratico" che a volte mandava tutto a rotoli.

La versione "fallata":

Codice sorgente - presumibilmente Windows

  1. DWORD EliminaUltimaPartePercorso( char *pc, DWORD lp ) {
  2.     for( --lp; pc[lp]!='\\' && pc[lp]!='/' && lp>=0; --lp )
  3.         pc[lp] = '\0';
  4.     return lstrlen( pc );
  5. }



La versione revisionata:

Codice sorgente - presumibilmente Windows

  1. DWORD EliminaUltimaPartePercorso( char *pc, DWORD lp ) {
  2.     for( --lp; pc[lp]!='\\' && pc[lp]!='/' && lp>=0; --lp )
  3.         pc[lp] = '\0';
  4.  
  5.     // se il percorso "tagliato" termina con un carattere
  6.     // '\\', elimina l'ultimo carattere del percorso
  7.     if( pc[lp] == '\\' || pc[lp] == '/' )
  8.         pc[lp] = '\0';
  9.     else --lp;
  10.  
  11.     return lp;
  12. }



Tutto sperando che in fase di testing non vengano fuori altri problemi...

PM Quote
Avatar
()
Newbie


Messaggi:
Iscritto:

Segnala al moderatore
Postato alle 20:06
Martedì, 11/11/2014
Questa sera, dopo il lavoro, ho provato qualche ulteriore test ed ho scoperto una cosa che, se vera, ha dell'incredibile: pare che XP dia come esito di GetModuleFileName() una stringa non zero-terminata, mentre Windows 7 pare dare come esito una stringa zero-terminata. Se venisse confermata questa situazione, direi che Microsoft ha fatto una figura barbina: cambiare una funzione senza cambiarne il nome o i parametri (in modo da rendere impossibile ogni forma di confusione) è uno sgambetto che non ci si aspetterebbe da una ditta seria.

Ora RicavaPercorsoProgramma() funziona sul mio XP come sul mio Windows 7 di casa. Domani vedrò come si comporta sui computer "blindati" della scuola, con un mix di XP, 7 e 8.

Codice sorgente - presumibilmente C++

  1. BOOL RicavaPercorsoProgramma( HINSTANCE hndIstanza, LPSTR *pBuffer ) {
  2.     try {
  3.         int dimPerc = 0; // dimensioni del percorso
  4.         int dimBuff = 0; // dimensioni del buffer
  5.         char *buffer = NULL;
  6.  
  7.         do {
  8.             delete[] buffer;
  9.             dimBuff += MAX_PATH;
  10.             buffer = new char[dimBuff];
  11.             dimPerc = GetModuleFileName( hndIstanza, buffer, dimBuff );
  12.             if( dimPerc == 0 ) { delete[] buffer; return FALSE; }
  13.         } while( dimPerc >= dimBuff );
  14.  
  15.         buffer[dimPerc] = '\0'; // XP non termina la stringa, Windows 7 sì!!!
  16.  
  17.         dimPerc = EliminaUltimaPartePercorso( buffer, dimPerc );
  18.         if( dimPerc>1 && buffer[dimPerc-1]==':' )
  19.             { buffer[dimPerc]='\\'; buffer[++dimPerc]='\0'; }
  20.  
  21.         if( dimPerc >= 0 ) {
  22.             delete[] buffer;
  23.             buffer = new char[dimPerc+1];
  24.             GetModuleFileName( hndIstanza, buffer, dimPerc+1 );
  25.             buffer[dimPerc] = '\0'; // XP non termina la stringa, Windows 7 sì!!!
  26.         }
  27.  
  28.         *pBuffer = buffer;
  29.  
  30.         return TRUE;
  31.     } catch( ... ) {
  32.         return FALSE;
  33.     }
  34. }
  35.  
  36.  
  37. DWORD EliminaUltimaPartePercorso( char *pc, DWORD lp ) {
  38.     for( --lp; pc[lp]!='\\' && pc[lp]!='/' && lp>=0; --lp )
  39.         pc[lp] = '\0';
  40.  
  41.     // se il percorso "tagliato" termina con un carattere '\\', elimina
  42.     // l'ultimo carattere del percorso; per evitare problemi dovuti ai
  43.     // "capricci" di Microsoft, termina la stringa
  44.     if( pc[lp] == '\\' || pc[lp] == '/' )
  45.         pc[lp] = '\0';
  46.     else pc[--lp] = '\0';
  47.  
  48.     return lp;
  49. }


PM Quote
Avatar
nessuno (Normal User)
Guru^2


Messaggi: 6402
Iscritto: 03/01/2010

Segnala al moderatore
Postato alle 21:32
Martedì, 11/11/2014
Nessuna figura di MS ... la documentazione dice chiaramente che XP, se il buffer non è sufficiente, restituisce una stringa non terminata da zero.

Ed effettivamente è così. Ma è un problema facilmente aggirabile ...


Ricorda che nessuno è obbligato a risponderti e che nessuno è perfetto ...
---
Il grande studioso italiano Bruno de Finetti ( uno dei padri fondatori del moderno Calcolo delle probabilità ) chiamava il gioco del Lotto Tassa sulla stupidità.
PM Quote
Pagine: [ 1 2 ] Precedente | Prossimo