Formati immagini dll c++ importate in c#

martedì 23 settembre 2008 - 09.44

Sagav123 Profilo | Newbie

Salve a tutti ho bisogno di aiuto, il problema può sembrare semplice ma data la mia inesperienza non è banale.
ho un progetto win form c# e una dll c++ devo:
prelevere l'immagine presente in un controllo picture box
passarlo alla dll scritta min c++
disegnare qualcosa sull'immagine
ripassare l'immagine a c#
la funzione sarà del tipo IMMAGINE_OUTPUT disegana(IMMAGINE_INPUT);
e sarà implementatta nella dll c++ e importata tramite un "dll import "
Il mio problema è come passare l'immagine o il riferimento ad essa tra i due linguaggi/sistemi insomma di che tipo sono IMMAGINE _INPUT E IMMAGINE_OUTPUT? come si gestiscono?
grazie in anticipo per l'aiuto a presto.

Brainkiller Profilo | Guru

>Salve a tutti ho bisogno di aiuto, il problema può sembrare semplice
>ma data la mia inesperienza non è banale.

Di solito sconsiglio a chi ha poca esperienza di mettersi su campi minati.

>ho un progetto win form c# e una dll c++ devo:
>prelevere l'immagine presente in un controllo picture box
>passarlo alla dll scritta min c++
>disegnare qualcosa sull'immagine
>ripassare l'immagine a c#

Io non l'ho mai fatto ma penso che tu possa passare l'Handle dell'oggetto Graphics (che è un device context) con GetHdc() alla funzione in VC++ la quale disegna sopra il device context e te lo ritorna.

Potrebbe essere anche passata come un array di byte o addirittura salvarla su disco e riaprirla da VC++ così passi solo il path.

Preparati a perdere un bel po' di tempo.
Ciao

David De Giacomi | Microsoft MVP
http://blogs.dotnethell.it/david/

Sagav123 Profilo | Newbie

hai perfettamete ragione ma il tempo e il mal di test li ho gia messi in conto...grazie per l'avvertimento.
cerco di chiarirti la mia situazione...o incasinarla non so.

il progetto c++ contiene:

imageCPP.h che suona piu o nemo cosi:

extern "C" HBITMAP __declspec(dllexport) __cdecl loadAndReturn(???? image_in);

imaceCPP.cpp che funziona circa cosi:

extern "C" HBITMAP _declspec(dllexport) __cdecl loadAndReturn(??? image_in)

{
//here i NEED to convert image_in in hbitmap format
//here i NEED to somethink with image_in
return image_in;
}

mentre nel progetto c#
ho una calsse che contiene i dll import

[DllImport("C:.......\.\.\imageCPP.dll")]
public static extern System.IntPtr loadAndReturn(???? image_in);

e uso la funzione all'incirca in questo modo:

???? image in;
System.IntPtr immagine_out;

immagine_out=importclass. loadAndReturn(image_in);
picturebox.Image = System.Drawing.Image.FromHbitmap(immagine_out);

riesco a restituire un immagine valida ovvero immagine_out cariacndola da file all'ìinterno della dll cio che non riesco a fare e passare una valida immagine alla dll da c# per elaborarla
grazie mille per l'aiuto ciao

aiedail92 Profilo | Expert

Ciao

Una volta che passi l'handle di sistema dell'immagine (quello che in C++ è un HBITMAP e in C# viene considerato un IntPtr) alla funzione scritta in C++, il problema del tipo di ritorno non si presenta più: se quello che devi fare è modificare un'immagine esistente (che quindi hai già caricato e di cui conosci già l'handle) non c'è bisogno di riottenere l'handle, perchè lo hai già. Per cui puoi impostare il tipo di ritorno su void, o al massimo su bool per ottenere o meno la riuscita della chiamata. Per quanto riguarda il tipo del parametro della funzione in C++, puoi definirlo semplicemente come HBITMAP, quindi questa diviene la firma della funzione C++:

extern "C" __declspec(dllexport) bool DisegnaQualcosa(HBITMAP image_in);

E questa una sua possibile implementazione:

extern "C" __declspec(dllexport) bool DisegnaQualcosa(HBITMAP image_in) { //Ottiene un'icona da disegnare sull'immagine HICON icon = LoadIcon(NULL, IDI_HAND); //Crea un DC HDC hdc = CreateCompatibleDC(NULL); //Salva lo stato del DC int st1 = SaveDC(hdc); //Seleziona l'immagine nel DC if(!SelectObject(hdc, image_in)) { //Se l'operazione fallisce libera la memoria e ritorna false DeleteDC(hdc); return false; } //Copia l'icona DrawIcon(hdc, 0, 0, icon); //Rilascia la memoria RestoreDC(hdc, st1); DeleteDC(hdc); DestroyIcon(icon); //ritorna true return true; }

Per richiamarla da C# il prototipo della funzione diventa questo:

[DllImport(@"percorso\nome.dll")] static extern bool DisegnaQualcosa(IntPtr image_in);

E il modo di utilizzarla da C# potrebbe essere questo (in alternativa puoi mettere Bitmap come valore di ritorno):

bool DisegnaQualcosaWrapper(ref Bitmap image) { //Ottiene l'handle di immagine per la bitmap IntPtr hImg = image.GetHbitmap(); //Esegue la funzione dalla dll if (!DisegnaQualcosa(hImg)) { //Elimina l'oggetto GDI e ritorna false DeleteObject(hImg); return false; } //A questo punto l'immagine non contiene i dati modificati, perchè //sono memorizzati in hImg, quindi crea una nuova immagine da hImg Bitmap newBmp = (Bitmap)Bitmap.FromHbitmap(hImg); //La vecchia immagine diventa quella nuova image = newBmp; //ritorna true return true; }

Luca

Sagav123 Profilo | Newbie

Grazie mille sono grazie al tuo aiuto sono riuscito a risolvere
ho usato "miabitmap.GetHbitmap();" funzione che ottienne ll'hanle desiderato.
Ora avrei un altro problemino...

Ho un codice c#
Image Buffrer1;
Image Buffrer2;
//initialize Buffer1;
//initialize Buffer1;
picturebox1= Buffer1 ;
Buffer2=Buffer1;
//modifie Buffer1 !!!
picturebox2= Buffer2 ;

Il fatto è che dopo aver inizializzato i Buffer1 e 2 vorrei tenere in memoria, senza scrivere su disco,
il contenuto dell'immagine in Burrer1 e mostrarlo in una seconda picturebox.
Il problema e che dopo aver modificato Buffer1 anche Buffer2 risulta modificato.
Come posso disaccoppiare i due buffer?

aiedail92 Profilo | Expert

Il codice cha hai usato non va bene perchè Image è una classe, quindi un tipo rifermento. Quello che succede quando fai

Buffer2 = Buffer1;

È che assegni alla variabile Buffer2 lo stesso oggetto a cui punta Buffer1, per cui modificando Buffer1 il contenuto sarà lo stesso in Buffer2.

Quello che devi fare invece è costruire un nuovo oggetto identico al primo, in questo caso puoi usare il costruttore di Bitmap, passando come argomento l'immagine di cui fare la copia:

Buffer2 = new Bitmap(Buffer1);

Luca

Sagav123 Profilo | Newbie

grazie mille ora ho capito
ma se volessi riassegnare il valore di Buffer2
al di fuori di una new ovveto dopo:
buffer2= new Bitmap(buffer1);
devo richiamare la new o posso usare un metodo alternativo?
lo chiedo perchè ho il sospetto che chiamare svariate new porterebbe ad un superlavoro per il garbage collector...

aiedail92 Profilo | Expert

I metodi alternativi ci sono, ma comunque tu faccia, il framework allocherà comunque della memoria con una new. Comunque non devi preoccuparti del Grarbage Collector, perchè (almeno in teoria) è stato appositamente studiato per mettersi all'opera in modo da ridurre al minimo l'utilizzo di memoria e massimizzare le prestazioni.

Tanto per farti un esempio, un metodo alternativo che potresti usare è la funzione statica Image.FromHbitmap, passando come argomento l'IntPtr ottenuto dall'immagine da copiare. Anche in questo caso però il framework chiamerà il costruttore Bitmap() e il Garbage Collector avrà il suo lavoro da fare.

Luca
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5