Oppure

Loading
02/10/14 14:46
Una cosa di cui mi capita spesso d'aver bisogno è il percorso della cartella del Desktop di Windows. Ho provato a elaborare una via per ricavarla "leggendo" il registro di sistema che vorrei proporre alla vostra attenzione.

// le variabili globali nelle quali immazzino il percorso del Desktop
DWORD gDPd = MAX_PATH;    // [g]lobale [D]imensioni [P]ercorso [d]esktop
BYTE gPd[MAX_PATH] = "";  // [g]lobale [P]ercorso [d]esktop

// il prototipo della funzione che "legge" il registro di sistema
LONG RicavaPercorsoShell( const char *nomeEl, HKEY chiave = HKEY_CURRENT_USER, int nLiv = 0 );

// una funzione per segnalare gli eventuali errori
void DescriviErroreRegistro( LONG id ) {
    char msg[128];
    FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, id, 0, msg, 127, NULL );
    MessageBox( NULL, msg, "Errore", MB_OK );
}

// l'implementazione delle funzione che "legge" il registro di sistema
LONG RicavaPercorsoShell( const char *nomeEl, HKEY chiave, int nLiv ) {
    static const int kTotLiv = 6;
    static const char *kNomiLiv[kTotLiv] = { "Software", "Microsoft",
        "Windows", "CurrentVersion", "Explorer", "Shell Folders" };

    static char buff[MAX_PATH];
    static DWORD dimBuff;
    LONG esito = ERROR_SUCCESS;
    int i;

    for( i=0; esito!=ERROR_NO_MORE_ITEMS && esito!=-1; ++i ) {
        dimBuff = MAX_PATH;

        esito = RegEnumKeyEx( chiave, i, buff, &dimBuff, 0, NULL, NULL, NULL );

        if( esito!=ERROR_SUCCESS && esito!=ERROR_NO_MORE_ITEMS ) goto uscita;

        if( lstrcmp(buff,kNomiLiv[nLiv]) == 0 ) {
            esito = RegOpenKeyEx( chiave, buff, 0, KEY_EXECUTE, &chiave );
            if( esito != ERROR_SUCCESS ) goto uscita;

            if( ++nLiv < kTotLiv ) { // chiama ricorsivamente se stessa
                esito = RicavaPercorsoShell( nomeEl, chiave, nLiv );
            }
            else { // ora e' aperta la chiave che contiene il percorso richiesto
                for( i=0, dimBuff=MAX_PATH;
                    esito!=ERROR_NO_MORE_ITEMS && esito!=-1;
                    ++i, dimBuff=MAX_PATH ) {

                    esito = RegEnumValue(
                        chiave, i, buff, &dimBuff, 0, NULL, gPd, &gDPd );

                    if( esito != ERROR_SUCCESS &&
                        esito != ERROR_MORE_DATA &&
                        esito != ERROR_NO_MORE_ITEMS ) {
                        *gPd = 'Una cosa di cui mi capita spesso d'aver bisogno è il percorso della cartella del Desktop di Windows. Ho provato a elaborare una via per ricavarla "leggendo" il registro di sistema che vorrei proporre alla vostra attenzione.


// le variabili globali nelle quali immazzino il percorso del Desktop
DWORD gDPd = MAX_PATH;    // [g]lobale [D]imensioni [P]ercorso [d]esktop
BYTE gPd[MAX_PATH] = "";  // [g]lobale [P]ercorso [d]esktop

// il prototipo della funzione che "legge" il registro di sistema
LONG RicavaPercorsoShell( const char *nomeEl, HKEY chiave = HKEY_CURRENT_USER, int nLiv = 0 );

// una funzione per segnalare gli eventuali errori
void DescriviErroreRegistro( LONG id ) {
    char msg[128];
    FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, id, 0, msg, 127, NULL );
    MessageBox( NULL, msg, "Errore", MB_OK );
}

// l'implementazione delle funzione che "legge" il registro di sistema
LONG RicavaPercorsoShell( const char *nomeEl, HKEY chiave, int nLiv ) {
    static const int kTotLiv = 6;
    static const char *kNomiLiv[kTotLiv] = { "Software", "Microsoft",
        "Windows", "CurrentVersion", "Explorer", "Shell Folders" };

    static char buff[MAX_PATH];
    static DWORD dimBuff;
    LONG esito = ERROR_SUCCESS;
    int i;

    for( i=0; esito!=ERROR_NO_MORE_ITEMS && esito!=-1; ++i ) {
        dimBuff = MAX_PATH;

        esito = RegEnumKeyEx( chiave, i, buff, &dimBuff, 0, NULL, NULL, NULL );

        if( esito!=ERROR_SUCCESS && esito!=ERROR_NO_MORE_ITEMS ) goto uscita;

        if( lstrcmp(buff,kNomiLiv[nLiv]) == 0 ) {
            esito = RegOpenKeyEx( chiave, buff, 0, KEY_EXECUTE, &chiave );
            if( esito != ERROR_SUCCESS ) goto uscita;

            if( ++nLiv < kTotLiv ) { // chiama ricorsivamente se stessa
                esito = RicavaPercorsoShell( nomeEl, chiave, nLiv );
            }
            else { // ora e' aperta la chiave che contiene il percorso richiesto
                for( i=0, dimBuff=MAX_PATH;
                    esito!=ERROR_NO_MORE_ITEMS && esito!=-1;
                    ++i, dimBuff=MAX_PATH ) {

                    esito = RegEnumValue(
                        chiave, i, buff, &dimBuff, 0, NULL, gPd, &gDPd );

                    if( esito != ERROR_SUCCESS &&
                        esito != ERROR_MORE_DATA &&
                        esito != ERROR_NO_MORE_ITEMS ) {
                        *gPd = '{parsed_message}';
                        goto uscita;
                    }

                    if( lstrcmp(buff,nomeEl)==0 ) esito = -1;
                }
            }
        }
    }

    uscita:

    if( chiave != 0 ) {
        RegCloseKey( chiave );
        chiave = 0;
    }

    return esito;
}


Sul Windows 7 sul quale ho testato il metodo la soluzione funziona, ma mi chiedo se sia un metodo affidabile o se possa essere fonte di disguidi. Chi volesse darci un'occhiata tenga presente che son solito chiamare la funzione una sola volta al momento dell'avvio del programma e memorizzare il percorso del Desktop in una variabile globale per usi futuri.

Posso migliorare qualcosa? Conviene cambiare completamente approccio? Che ne dite?

P.S. xPiero: E' abbastanza spaghettico? :)'; goto uscita; } if( lstrcmp(buff,nomeEl)==0 ) esito = -1; } } } } uscita: if( chiave != 0 ) { RegCloseKey( chiave ); chiave = 0; } return esito; }


Sul Windows 7 sul quale ho testato il metodo la soluzione funziona, ma mi chiedo se sia un metodo affidabile o se possa essere fonte di disguidi. Chi volesse darci un'occhiata tenga presente che son solito chiamare la funzione una sola volta al momento dell'avvio del programma e memorizzare il percorso del Desktop in una variabile globale per usi futuri.

Posso migliorare qualcosa? Conviene cambiare completamente approccio? Che ne dite?

P.S. xPiero: E' abbastanza spaghettico? :)
02/10/14 15:40
Mah ... a parte il fatto che al posto dei tre

goto uscita

avrei scritto semplicemente

break;

la questione è un'altra ... perché leggi da registro per ottenere la cartella del desktop?
Personalmente farei con queste 3 righe

#include <Shlobj.h>

TCHAR desk[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, desk);
02/10/14 16:45
Ci sono delle ragioni (magari sciocche, non so) almeno per l'ultimo dei goto. Se uso un break al posto dell'ultimo goto esco dal ciclo for più interno ma non da quello più esterno. Siccome il for interno reinizializza i su 0, se torno al for esterno entro in un ciclo infinito (è ben vero che avrei potuto usare un contatore diverso, con una variabile apposita). Questo se ho seguito ragionamenti sensati, e non è detta...

In merito all'usare o non usare SHGetFolderPath(), devo ammettere che ci ho provato, ma probabilmente non sono riuscito a capire bene la documentazione, perché il compilatore continuava a lamentarsi per l'impossibilità di usare quella funzione; un po' piccato, per questo ho di malavoglia elaborato la mia soluzione schizofrenica.

Vedo che hai incluso un "misterioso" header Shlobj.h... magari quello rende il compilatore un po' più "collaborativo", ci proverò. Devo anche collegare qualche libreria? Tipo quando includi gdiplus.h, intendo, e devi dare istruzione al linker di collegare gdiplus.lib.

Certo è che se mi funziona SHGetFolderPath() butto via alla velocità della luce la mia funzione "barocca"! Tre righe di codice sono effettivamente meglio di settanta, e poi c'è il rischio affidabilità che adombravo.

EDIT (qualche minuto dopo):

Uàaaaaa!!! Includendo shlobj.h funziona alla grande. Certo è che se quei buontemponi che han scritto la documentazione nascondono le informazioni sotto al tappeto non è che uno se le può sognare. Grazie mille, da solo avrei continuato a seguire una strada inutilmente tortuosa e probabilmente inaffidabile. SHGetFolderPath() mi sarà senz'altro utile in mille circostanze (anche se su msdn l'hanno etichettata come "deprecated";). Nel cestino la mia funzione "barocca" e spaghettosa.
Ultima modifica effettuata da 02/10/14 17:07
02/10/14 18:29
Postato originariamente da AldoBaldo:
Ci sono delle ragioni (magari sciocche, non so) almeno per l'ultimo dei goto.


Sì, non avevo notato il secondo for e quindi per l'ultimo goto non basta un break ma è necessario una seconda if dopo la for che esegua un altro break. E' comunque meglio del goto.

Per la SHGetFolderPath() è deprecata perché praticamente usata fino ad XP (anche se funzionante).

Da Vista in poi dovresti usare la nuova funzione SHGetKnownFolderPath() in modo simile

	LPWSTR szPath;
	SHGetKnownFolderPath(FOLDERID_Desktop, 0, 0, &szPath);




Ultima modifica effettuata da 02/10/14 19:56
02/10/14 19:17
Postato originariamente da nessuno:
Da Vista in poi dovresti usare la nuova funzione SHGetKnownFolderPath() in modo simile

	TCHAR desk[MAX_PATH];
	SHGetKnownFolderPath(FOLDERID_Desktop, 0, NULL, desk);




Per qualche ragione questa versione non funziona sul mio Code::Blocks. La lamentela è questa:

||=== Build: Debug in Esperimento (compiler: GNU GCC Compiler) ===|
C:\...\main.cpp||In function 'int WinMain(HINSTANCE, HINSTANCE, LPSTR, int)':|
C:\...\main.cpp|48|error: 'FOLDERID_Desktop' was not declared in this scope|
C:\...\main.cpp|48|error: 'SHGetKnownFolderPath' was not declared in this scope|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 2 second(s)) ===|


E' come se il file di intestazione non facesse a modo il suo dovere.
02/10/14 19:19
Quale sistema operativo usi? Quale versione di compilatore?
02/10/14 20:00
Il sistema operativo è Windows 7 Starter.
Il compilatore è il GNU GCC che veniva distribuito nell'installatore di Code::Blocks quando è uscita la versione 13.12 del programma. Il file "leggimi" contenuto nella cartella MinGW dice così:

=== TDM-GCC Compiler Suite for Windows ===
--- GCC 4.6 & 4.7 Series ---
*** Standard MinGW 32-bit Edition ***

Spero che siano dati esatti e sufficienti.
02/10/14 20:08
Non so quale sdk hai installato ma devi aggiornarlo.

Ad esempio, con VS2010 c'è già installato il 7.0A che va bene, ma puoi scaricarne anche uno più recente ed installarlo per il gcc e c::b ...

Ultima modifica effettuata da 02/10/14 20:09