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
C/C++ - GDI dà i numeri (o, più probabilmente, li do io)
Forum - C/C++ - GDI dà i numeri (o, più probabilmente, li do io)

Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 14:23
Domenica, 15/10/2017
Come suggerito da Nessuno, ripropongo qui il mio quesito:

Testo quotato

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):

Codice sorgente - presumibilmente C#

  1. /*==============================================================================
  2. La classica finestra di navigazione per l'individuazione dei file in Windows.
  3. "tipoFile" identifica il tipo di file che sara' riconosciuto dalla finestra di
  4. navigazione e che sarà usato come estensione di default, se del caso. Se e' NULL
  5. saranno accettati file di ogni tipo e non sara' attribuita alcuna estensione di
  6. default.
  7. "nomeFileDef" identifica il nome del file usato come default nella finestra del
  8. tipo "Salva". Se "nomeFileDef" e' un puntatore valido, la finestra usata sara'
  9. una finestra del tipo "Salva"; se e' NULL, la finestra usata sarà una finestra
  10. del tipo "Apri".
  11. ==============================================================================*/
  12.  
  13. const char *IdentificaFile ( HWND hwnd, const char *tipoFile,
  14.                              const char *nomeFileDef ) {
  15.     OPENFILENAME ofn;
  16.     char filtro[32];
  17.     char *p = filtro;
  18.     char *nomeFile;
  19.     DWORD esito;
  20.  
  21.     ZeroMemory(&ofn, sizeof(ofn));
  22.  
  23.     if( tipoFile != NULL ) {
  24.         p += wsprintf( p, "Tipo file: %s", tipoFile ) + 1;
  25.         p += wsprintf( p, "*.%s", tipoFile ) + 1;
  26.         *p = '\0';
  27.     }
  28.     else {
  29.         p += wsprintf( p, "Tutti i file (*.*)" ) + 1;
  30.         p += wsprintf( p, "*.*" ) + 1;
  31.         *p = '\0';
  32.     }
  33.  
  34.     nomeFile = (char *) calloc( 4*MAX_PATH, sizeof(*nomeFile) );
  35.     if( nomeFile == NULL ) return nomeFile;
  36.     *nomeFile = '\0';
  37.  
  38.     if( nomeFileDef != NULL )
  39.         lstrcpy( nomeFile, nomeFileDef );
  40.  
  41.     ofn.lStructSize = sizeof(ofn);
  42.     ofn.hwndOwner = hwnd;
  43.     ofn.lpstrFilter = filtro;
  44.     ofn.lpstrFile = nomeFile;
  45.     ofn.nMaxFile = MAX_PATH;
  46.     ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST |
  47.                 OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
  48.     ofn.lpstrDefExt = tipoFile;
  49.  
  50.     if( nomeFileDef != NULL )
  51.         esito = GetSaveFileName( &ofn );
  52.     else esito = GetOpenFileName( &ofn );
  53.  
  54.     if( esito == FALSE ) {
  55.         Errore( CommDlgExtendedError(), hwnd );
  56.         free( nomeFile ); nomeFile = NULL;
  57.     }
  58.  
  59.     return nomeFile;
  60. }



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.
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 14:31
Domenica, 15/10/2017
La funzione nella quale Gdiplus segnala i suoi OutOfMemory (solo nelle condizioni che ho già spiegato) è questa:

Codice sorgente - presumibilmente C++

  1. Image *CaricaSprite( const WCHAR *nome_file ) {
  2.     try {
  3.         Image *imgTmp = new Image( nome_file );
  4.         if( imgTmp->GetLastStatus() != Ok )
  5.             { delete imgTmp; imgTmp = NULL; }
  6.         return imgTmp;
  7.     } catch( ... ) {
  8.         return NULL;
  9.     }
  10. }



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().

Codice sorgente - presumibilmente C++

  1. static const WCHAR kStrNomeFileSpriteSfondo[]   = L"img\\sfondo.png";
  2. static const WCHAR kStrNomeFileSpritePercorso[] = L"img\\percorso.png";
  3. static const WCHAR kStrNomeFileSpriteModfBit[]  = L"img\\segnaposto.png";


Ultima modifica effettuata da AldoBaldo il 15/10/2017 alle 14: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.
PM Quote
Avatar
nessuno (Normal User)
Guru^2


Messaggi: 6402
Iscritto: 03/01/2010

Segnala al moderatore
Postato alle 14:49
Domenica, 15/10/2017
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.


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
nessuno (Normal User)
Guru^2


Messaggi: 6402
Iscritto: 03/01/2010

Segnala al moderatore
Postato alle 15:23
Domenica, 15/10/2017
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 nessuno il 15/10/2017 alle 15:29


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
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 20:32
Domenica, 15/10/2017
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 il 15/10/2017 alle 20: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.
PM Quote
Avatar
nessuno (Normal User)
Guru^2


Messaggi: 6402
Iscritto: 03/01/2010

Segnala al moderatore
Postato alle 20:42
Domenica, 15/10/2017
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.


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