Oppure

Loading
15/10/17 12:23
AldoBaldo
Come suggerito da Nessuno, ripropongo qui il mio quesito:

Mi succede una cosa strana...

Ho uno dei miei pasticciatissimi programmi in fase di "elaborazione", e mi ritrovo a voler caricare delle immagini con Gdiplus per mezzo di new Image(L"nomefile";). Controllo tutto il controllabile e, quando è il caso, distruggo regolarmente con delete l'oggetto Image creato.

Tutto funziona alla perfezione finché... incredibile... chiamo GetOpenFileName() o GetSaveFileName()! A quel punto sembra che GDI impazzisca. Dal task manager rilevo che le due funzioni creano una sessantina di oggetti GDI che non vengono distrutti che in minima parte, e le mie successive chiamate a new Image(L"nomefile";) falliscono miseramente con GetLastStatus() che restituisce OutOfMemory (il che, francamente, mi sembra assurdo perché il task manager mi informa che sono ancora disponibili circa 1,3 GB di memoria fisica liberi).

Qualcuno qui ha idea di cosa sta succedendo? Perché ho già provato qualsiasi verifica col debugger e non trovo nessun altro errore. Dico nessuno. Sono evidentemente cieco, oppure è il sistema che fa cose strane (probabilmente perché m'è sfuggito qualche passaggio della documentazione, che pure ho letto e riletto non so quante volte)...


I problemi si manifestano esclusivamente dopo la chiamata a GetOpenFileName() o a GetSaveFileName() in questa funzione (cancellando le chiamate al sistema, la funzione non dà inconvenienti):

/*==============================================================================
La classica finestra di navigazione per l'individuazione dei file in Windows.
"tipoFile" identifica il tipo di file che sara' riconosciuto dalla finestra di
navigazione e che sarà usato come estensione di default, se del caso. Se e' NULL
saranno accettati file di ogni tipo e non sara' attribuita alcuna estensione di
default.
"nomeFileDef" identifica il nome del file usato come default nella finestra del
tipo "Salva". Se "nomeFileDef" e' un puntatore valido, la finestra usata sara'
una finestra del tipo "Salva"; se e' NULL, la finestra usata sarà una finestra
del tipo "Apri".
==============================================================================*/

const char *IdentificaFile ( HWND hwnd, const char *tipoFile,
                             const char *nomeFileDef ) {
    OPENFILENAME ofn;
    char filtro[32];
    char *p = filtro;
    char *nomeFile;
    DWORD esito;

    ZeroMemory(&ofn, sizeof(ofn));

    if( tipoFile != NULL ) {
        p += wsprintf( p, "Tipo file: %s", tipoFile ) + 1;
        p += wsprintf( p, "*.%s", tipoFile ) + 1;
        *p = 'Come suggerito da Nessuno, ripropongo qui il mio quesito:


Mi succede una cosa strana...

Ho uno dei miei pasticciatissimi programmi in fase di "elaborazione", e mi ritrovo a voler caricare delle immagini con Gdiplus per mezzo di new Image(L"nomefile";). Controllo tutto il controllabile e, quando è il caso, distruggo regolarmente con delete l'oggetto Image creato.

Tutto funziona alla perfezione finché... incredibile... chiamo GetOpenFileName() o GetSaveFileName()! A quel punto sembra che GDI impazzisca. Dal task manager rilevo che le due funzioni creano una sessantina di oggetti GDI che non vengono distrutti che in minima parte, e le mie successive chiamate a new Image(L"nomefile";) falliscono miseramente con GetLastStatus() che restituisce OutOfMemory (il che, francamente, mi sembra assurdo perché il task manager mi informa che sono ancora disponibili circa 1,3 GB di memoria fisica liberi).

Qualcuno qui ha idea di cosa sta succedendo? Perché ho già provato qualsiasi verifica col debugger e non trovo nessun altro errore. Dico nessuno. Sono evidentemente cieco, oppure è il sistema che fa cose strane (probabilmente perché m'è sfuggito qualche passaggio della documentazione, che pure ho letto e riletto non so quante volte)...


I problemi si manifestano esclusivamente dopo la chiamata a GetOpenFileName() o a GetSaveFileName() in questa funzione (cancellando le chiamate al sistema, la funzione non dà inconvenienti):

/*==============================================================================
La classica finestra di navigazione per l'individuazione dei file in Windows.
"tipoFile" identifica il tipo di file che sara' riconosciuto dalla finestra di
navigazione e che sarà usato come estensione di default, se del caso. Se e' NULL
saranno accettati file di ogni tipo e non sara' attribuita alcuna estensione di
default.
"nomeFileDef" identifica il nome del file usato come default nella finestra del
tipo "Salva". Se "nomeFileDef" e' un puntatore valido, la finestra usata sara'
una finestra del tipo "Salva"; se e' NULL, la finestra usata sarà una finestra
del tipo "Apri".
==============================================================================*/

const char *IdentificaFile ( HWND hwnd, const char *tipoFile,
                             const char *nomeFileDef ) {
    OPENFILENAME ofn;
    char filtro[32];
    char *p = filtro;
    char *nomeFile;
    DWORD esito;

    ZeroMemory(&ofn, sizeof(ofn));

    if( tipoFile != NULL ) {
        p += wsprintf( p, "Tipo file: %s", tipoFile ) + 1;
        p += wsprintf( p, "*.%s", tipoFile ) + 1;
        *p = '{parsed_message}';
    }
    else {
        p += wsprintf( p, "Tutti i file (*.*)" ) + 1;
        p += wsprintf( p, "*.*" ) + 1;
        *p = '{parsed_message}';
    }

    nomeFile = (char *) calloc( 4*MAX_PATH, sizeof(*nomeFile) );
    if( nomeFile == NULL ) return nomeFile;
    *nomeFile = '{parsed_message}';

    if( nomeFileDef != NULL )
        lstrcpy( nomeFile, nomeFileDef );

    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = filtro;
    ofn.lpstrFile = nomeFile;
    ofn.nMaxFile = MAX_PATH;
    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST |
                OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
    ofn.lpstrDefExt = tipoFile;

    if( nomeFileDef != NULL )
        esito = GetSaveFileName( &ofn );
    else esito = GetOpenFileName( &ofn );

    if( esito == FALSE ) {
        Errore( CommDlgExtendedError(), hwnd );
        free( nomeFile ); nomeFile = NULL;
    }

    return nomeFile;
}


Prima che qualcuno faccia questa ipotesi, evidenzio subito che non ho commesso errori usando stringhe di WCHAR al posto di stringhe di char, anche perché il nome del file che ricavo con IdentificaFile() non lo uso con Gdiplus (e comunque il compilatore sputerebbe fuori segnalazione d'errore a raffica).'; } else { p += wsprintf( p, "Tutti i file (*.*)" ) + 1; p += wsprintf( p, "*.*" ) + 1; *p = 'Come suggerito da Nessuno, ripropongo qui il mio quesito:

Mi succede una cosa strana...

Ho uno dei miei pasticciatissimi programmi in fase di "elaborazione", e mi ritrovo a voler caricare delle immagini con Gdiplus per mezzo di new Image(L"nomefile";). Controllo tutto il controllabile e, quando è il caso, distruggo regolarmente con delete l'oggetto Image creato.

Tutto funziona alla perfezione finché... incredibile... chiamo GetOpenFileName() o GetSaveFileName()! A quel punto sembra che GDI impazzisca. Dal task manager rilevo che le due funzioni creano una sessantina di oggetti GDI che non vengono distrutti che in minima parte, e le mie successive chiamate a new Image(L"nomefile";) falliscono miseramente con GetLastStatus() che restituisce OutOfMemory (il che, francamente, mi sembra assurdo perché il task manager mi informa che sono ancora disponibili circa 1,3 GB di memoria fisica liberi).

Qualcuno qui ha idea di cosa sta succedendo? Perché ho già provato qualsiasi verifica col debugger e non trovo nessun altro errore. Dico nessuno. Sono evidentemente cieco, oppure è il sistema che fa cose strane (probabilmente perché m'è sfuggito qualche passaggio della documentazione, che pure ho letto e riletto non so quante volte)...


I problemi si manifestano esclusivamente dopo la chiamata a GetOpenFileName() o a GetSaveFileName() in questa funzione (cancellando le chiamate al sistema, la funzione non dà inconvenienti):

/*==============================================================================
La classica finestra di navigazione per l'individuazione dei file in Windows.
"tipoFile" identifica il tipo di file che sara' riconosciuto dalla finestra di
navigazione e che sarà usato come estensione di default, se del caso. Se e' NULL
saranno accettati file di ogni tipo e non sara' attribuita alcuna estensione di
default.
"nomeFileDef" identifica il nome del file usato come default nella finestra del
tipo "Salva". Se "nomeFileDef" e' un puntatore valido, la finestra usata sara'
una finestra del tipo "Salva"; se e' NULL, la finestra usata sarà una finestra
del tipo "Apri".
==============================================================================*/

const char *IdentificaFile ( HWND hwnd, const char *tipoFile,
                             const char *nomeFileDef ) {
    OPENFILENAME ofn;
    char filtro[32];
    char *p = filtro;
    char *nomeFile;
    DWORD esito;

    ZeroMemory(&ofn, sizeof(ofn));

    if( tipoFile != NULL ) {
        p += wsprintf( p, "Tipo file: %s", tipoFile ) + 1;
        p += wsprintf( p, "*.%s", tipoFile ) + 1;
        *p = '{parsed_message}';
    }
    else {
        p += wsprintf( p, "Tutti i file (*.*)" ) + 1;
        p += wsprintf( p, "*.*" ) + 1;
        *p = '{parsed_message}';
    }

    nomeFile = (char *) calloc( 4*MAX_PATH, sizeof(*nomeFile) );
    if( nomeFile == NULL ) return nomeFile;
    *nomeFile = '{parsed_message}';

    if( nomeFileDef != NULL )
        lstrcpy( nomeFile, nomeFileDef );

    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = filtro;
    ofn.lpstrFile = nomeFile;
    ofn.nMaxFile = MAX_PATH;
    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST |
                OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
    ofn.lpstrDefExt = tipoFile;

    if( nomeFileDef != NULL )
        esito = GetSaveFileName( &ofn );
    else esito = GetOpenFileName( &ofn );

    if( esito == FALSE ) {
        Errore( CommDlgExtendedError(), hwnd );
        free( nomeFile ); nomeFile = NULL;
    }

    return nomeFile;
}


Prima che qualcuno faccia questa ipotesi, evidenzio subito che non ho commesso errori usando stringhe di WCHAR al posto di stringhe di char, anche perché il nome del file che ricavo con IdentificaFile() non lo uso con Gdiplus (e comunque il compilatore sputerebbe fuori segnalazione d'errore a raffica).'; } nomeFile = (char *) calloc( 4*MAX_PATH, sizeof(*nomeFile) ); if( nomeFile == NULL ) return nomeFile; *nomeFile = 'Come suggerito da Nessuno, ripropongo qui il mio quesito:

Mi succede una cosa strana...

Ho uno dei miei pasticciatissimi programmi in fase di "elaborazione", e mi ritrovo a voler caricare delle immagini con Gdiplus per mezzo di new Image(L"nomefile";). Controllo tutto il controllabile e, quando è il caso, distruggo regolarmente con delete l'oggetto Image creato.

Tutto funziona alla perfezione finché... incredibile... chiamo GetOpenFileName() o GetSaveFileName()! A quel punto sembra che GDI impazzisca. Dal task manager rilevo che le due funzioni creano una sessantina di oggetti GDI che non vengono distrutti che in minima parte, e le mie successive chiamate a new Image(L"nomefile";) falliscono miseramente con GetLastStatus() che restituisce OutOfMemory (il che, francamente, mi sembra assurdo perché il task manager mi informa che sono ancora disponibili circa 1,3 GB di memoria fisica liberi).

Qualcuno qui ha idea di cosa sta succedendo? Perché ho già provato qualsiasi verifica col debugger e non trovo nessun altro errore. Dico nessuno. Sono evidentemente cieco, oppure è il sistema che fa cose strane (probabilmente perché m'è sfuggito qualche passaggio della documentazione, che pure ho letto e riletto non so quante volte)...


I problemi si manifestano esclusivamente dopo la chiamata a GetOpenFileName() o a GetSaveFileName() in questa funzione (cancellando le chiamate al sistema, la funzione non dà inconvenienti):

/*==============================================================================
La classica finestra di navigazione per l'individuazione dei file in Windows.
"tipoFile" identifica il tipo di file che sara' riconosciuto dalla finestra di
navigazione e che sarà usato come estensione di default, se del caso. Se e' NULL
saranno accettati file di ogni tipo e non sara' attribuita alcuna estensione di
default.
"nomeFileDef" identifica il nome del file usato come default nella finestra del
tipo "Salva". Se "nomeFileDef" e' un puntatore valido, la finestra usata sara'
una finestra del tipo "Salva"; se e' NULL, la finestra usata sarà una finestra
del tipo "Apri".
==============================================================================*/

const char *IdentificaFile ( HWND hwnd, const char *tipoFile,
                             const char *nomeFileDef ) {
    OPENFILENAME ofn;
    char filtro[32];
    char *p = filtro;
    char *nomeFile;
    DWORD esito;

    ZeroMemory(&ofn, sizeof(ofn));

    if( tipoFile != NULL ) {
        p += wsprintf( p, "Tipo file: %s", tipoFile ) + 1;
        p += wsprintf( p, "*.%s", tipoFile ) + 1;
        *p = '{parsed_message}';
    }
    else {
        p += wsprintf( p, "Tutti i file (*.*)" ) + 1;
        p += wsprintf( p, "*.*" ) + 1;
        *p = '{parsed_message}';
    }

    nomeFile = (char *) calloc( 4*MAX_PATH, sizeof(*nomeFile) );
    if( nomeFile == NULL ) return nomeFile;
    *nomeFile = '{parsed_message}';

    if( nomeFileDef != NULL )
        lstrcpy( nomeFile, nomeFileDef );

    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = hwnd;
    ofn.lpstrFilter = filtro;
    ofn.lpstrFile = nomeFile;
    ofn.nMaxFile = MAX_PATH;
    ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST |
                OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
    ofn.lpstrDefExt = tipoFile;

    if( nomeFileDef != NULL )
        esito = GetSaveFileName( &ofn );
    else esito = GetOpenFileName( &ofn );

    if( esito == FALSE ) {
        Errore( CommDlgExtendedError(), hwnd );
        free( nomeFile ); nomeFile = NULL;
    }

    return nomeFile;
}


Prima che qualcuno faccia questa ipotesi, evidenzio subito che non ho commesso errori usando stringhe di WCHAR al posto di stringhe di char, anche perché il nome del file che ricavo con IdentificaFile() non lo uso con Gdiplus (e comunque il compilatore sputerebbe fuori segnalazione d'errore a raffica).'; if( nomeFileDef != NULL ) lstrcpy( nomeFile, nomeFileDef ); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hwnd; ofn.lpstrFilter = filtro; ofn.lpstrFile = nomeFile; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY; ofn.lpstrDefExt = tipoFile; if( nomeFileDef != NULL ) esito = GetSaveFileName( &ofn ); else esito = GetOpenFileName( &ofn ); if( esito == FALSE ) { Errore( CommDlgExtendedError(), hwnd ); free( nomeFile ); nomeFile = NULL; } return nomeFile; }


Prima che qualcuno faccia questa ipotesi, evidenzio subito che non ho commesso errori usando stringhe di WCHAR al posto di stringhe di char, anche perché il nome del file che ricavo con IdentificaFile() non lo uso con Gdiplus (e comunque il compilatore sputerebbe fuori segnalazione d'errore a raffica).
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
15/10/17 12:31
AldoBaldo
La funzione nella quale Gdiplus segnala i suoi OutOfMemory (solo nelle condizioni che ho già spiegato) è questa:

Image *CaricaSprite( const WCHAR *nome_file ) {
    try {
        Image *imgTmp = new Image( nome_file );
        if( imgTmp->GetLastStatus() != Ok )
            { delete imgTmp; imgTmp = NULL; }
        return imgTmp;
    } catch( ... ) {
        return NULL;
    }
}


Il parametro nome_file viene sempre ed esclusivamente passato ricavandolo da una di tre costanti WCHAR[], per cui NON PUO' interferire con il nome del file passato da IdentificaFile().

static const WCHAR kStrNomeFileSpriteSfondo[]   = L"img\sfondo.png";
static const WCHAR kStrNomeFileSpritePercorso[] = L"img\percorso.png";
static const WCHAR kStrNomeFileSpriteModfBit[]  = L"img\segnaposto.png";
Ultima modifica effettuata da AldoBaldo 15/10/17 12:33
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
15/10/17 12:49
A parte la calloc con

4 * MAX_PATH, sizeof(*nomeFile)

di cui non capisco il perché della grandezza e sperando che la stessa venga liberata dalla funzione chiamante, non trovo particolari problemi (io avrei usato stringhe del C++, ma non p questo il problema) ...

L'ho usata, anche con GDI+ e non mi ha dato problemi.

Quindi il problema è nella sua chiamata o da qualche altra parte.
15/10/17 13:23
Per la precisione ho scritto un piccolo main con questi blocchi


- startup di GdiPlus (obbligatorio)

- chiamata a IdentificaFile

- chiamata a CaricaSprite (con costante)

- visualizzazione (con graphics.DrawImage)

- shutdown di GdiPlus (obbligatoria)


e non ho avuto problemi.
Ultima modifica effettuata da 15/10/17 13:29
15/10/17 18:32
AldoBaldo
Il 4x è giusta una fisima, diciamo un eccesso (inutile) di prudenza. Mi basta poco per avere quel senso di tranquillità che ti aggiusta una mezz'ora.

Sai che faccio, a questo punto? Apro un progetto qui su Pierotofy così carico tutto il programma e magari vedendo l'insieme (se ne hai voglia) scopri l'inghippo. A me continua a sfuggire.

P.S. Ora ne provo un'altra, che sembra stupida: riavvio il PC e vedo che accade. Hai visto mai...
Ultima modifica effettuata da AldoBaldo 15/10/17 18:32
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
15/10/17 18:42
E' una fisima inutile ... devi programmare con criterio, sapendo quello che fai ...

Per il progetto, va bene, ma indica anche dove si presenta il problema nel codice.