Visualizzazione dei risultati da 1 a 9 su 9
  1. #1
    Utente di HTML.it
    Registrato dal
    Jun 2010
    Messaggi
    250

    [C#] Problema con passaggio di puntatori

    Salve ragazzi,sono nuovo del mondo C# ed ho un problema che non so veramente come risolvere.
    In pratica ho creato una classe con delle funzioni prelevate da una dll appositamente da me creata (questa dll è stata creata in codice C).
    Innanzitutto il metodo che voglio richiamare è un metodo che restituisce un char pointer;quando vado a richiamare il metodo in modo opportuno,assegno il valore restituito ad una variabile (di tipo conforme a quello restituito dal metodo..ovviamente)...ma quando vado a stampare il carattere puntato da quell'indirizzo non riesco a visualizzare il risultato atteso.
    Aggiungo anche che sotto un compilatore C la funzione funziona correttamente quindi escluderei un problema di codice all'interno della dll.
    Il codice della classe è il seguente:
    codice:
     
    namespace WindowsFormsApplication1
    {
        
        public class Classe1
        {
          [DllImport("PERCORSODELLADLL")]
          unsafe public static extern char* funz(char[] parola);
    
          unsafe public static char* funz_(char[] parola)
          {
             return funz(parola);
           }
    Poi vado a richiamare iil metodo in questo modo:
    codice:
    char[] parola = {'c','i','a','o'};
    unsafe {
                 
                 char *p;
                  p = Classe1.funz_(parola);
              }
    Questo è tutto...spero sia stato abbastanza chiaro ad esporre il mio problema e spero anche che riusciate a darmi una mano..Confido su di voi!!!

  2. #2
    Ciao Marco1995,

    dal tuo messaggio non è perfettamente chiaro se ciò che ritorna la funzione è un singolo carattere o una stringa, ma propendo per il secondo caso.
    Premetto subito che non è affatto banale ritornare una stringa tramite una funzione esportata da una DLL, dato che c'è sempre il grosso rischio di memory leak. Quando eventuali alternative non sono percorribili (come presumo in questo caso), bisogna quindi fare molta attenzione nell'allocazione all'interno della DLL, usando l'API giusta.

    In ogni caso non è necessario utilizzare contesti unsafe per dichiarare la funzione che hai creato, C# ci viene in soccorso nel marshalling facendo già tutto per noi, compresa la deallocazione della stringa una volta chiamata la funzione.

    Come dicevo, l'allocazione (nella DLL C) NON DEVE essere fatta tramite new, malloc() o quant'altro, ma esclusivamente usando CoTaskMemAlloc().
    Quindi la funzione esportata apparirà simile a questa:

    #include [list=1] /* CoTaskMemAlloc */

    extern "C"
    {
    __declspec(dllexport) char* dllFunction(char *param)
    {
    static const char msg[] = "I love ";

    char* retString = (char*)CoTaskMemAlloc(sizeof(msg) + strlen(param));
    strcpy(retString, msg);
    strcat(retString, param);

    return retString;
    }
    }

    Lato C# a questo punto non resta molto da fare se non dichiarare la firma della funzione, con:

    [DllImport("test_lib.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
    public static extern string dllFunction(string param);

    Da notare gli attributi CharSet (stiamo parlando di stringhe C, quindi per default non Unicode) e la CallingConvention, Cdecl, normalmente usata da C/C++.
    Come puoi vedere non è necessario usare la keyword unsafe perchè il marshalling viene fatto in automatico, usando comodissime string.

    Non resta altro che chiamare la nostra funzione con un metodo della classe:

    public string test(string param)
    {
    return dllFunction(param);
    }

    E chiamando il tutto nel Main:

    Class1 class1 = new Class1();
    string retVal = class1.test("CSharp");
    Console.WriteLine("Messaggio: {0}", retVal);

    Otterremo su console qualcosa del tipo:

    Messaggio: I love CSharp

    Hope this help!!!


    Ciao


  3. #3
    Utente di HTML.it
    Registrato dal
    Jun 2010
    Messaggi
    250
    Innanzitutto ti ringrazio per la risposta veramente molto chiara ed esaustiva...ti faccio i complimenti anche perchè hai centrato appieno il mio problema ad ogni modo riscontro problemi all'atto della compilazione della libreria,in particolare con la nuova istruzione che mi hai suggerito:
    codice:
    CoTaskMemAlloc(parametro)
    L'errore riportato dal compilatore è questo:
    codice:
    Undefined reference to CoTaskMemAlloc@4
    Secondo quanto so questo errore dovrebbe essere causato dal fatto che non riesce a trovare la funzione (ma non vorrei dire caz*ate)...(ovviamente l'header ole2.h l'ho incuso sia nel file .cpp che nel file .h ).

    Un' ultima cosa...non ho ben capito perchè,dal punto di vista teorico,si debba utilizzare tale funzione (scusa se ti faccio questa domanda ma a me interessa di più capire i concetti teorici invece di un qualche esercizietto )

    Grazie ancora della pazienza e del tuo aiuto,attendo con ANSIA tue risposte

  4. #4
    L'errore di compilazione è dovuto quasi certamente al fatto che non stai importando la libreria OLE32 che definisce la funzione, come del resto hai giustamente ipotizzato tu. Verifica nelle proprietà del progetto che, sotto la categoria Linker/Input, nel campo Additional Dependencies, ci sia ole32.lib nell'elenco e, nel caso manchi, aggiungilo. Vedrai che in questo modo risolverai il problema.

    Senza entrare troppo nel dettaglio della questione, ti spiego brevemente perchè è necessario utilizzare CoTaskMemAlloc() in questo caso.
    Di fatto la DLL C e l'applicazione .NET sono due entità diverse e vivono in due ambienti isolati, pur coabitando nello stesso processo: ciò che viene creato in uno è visibile sono in quello e non nell'altro (e viceversa).
    La funzione della C standard library malloc() e la sua controparte new in C++ utilizzano l'heap per l'allocazione ma non sanno nulla di ciò che c'è all'esterno. Per scambiare dati che non siano di dimensione nota (e che quindi possono essere comodamente passati nello stack) è necessario trovare sistemi "comuni" ai due ecosistemi.
    A differenza di malloc() e new che vengono forniti dal compilatore, CoTaskMemAlloc() è una API del sistema operativo che alloca memoria sempre nello heap, ma che è accessibile ovunque nello stesso processo. Per dovere di cronaca c'è da dire che non è l'unica API in grado di fare ciò ma CoTaskMemAlloc() è quella che viene utilizzata quando si ha a che fare con oggetti COM perchè ne rende semplice il marshalling.
    Una cosa che ho dimenticato di dire nel post precedente è che nell'esempio riportato non c'è bisogno di deallocare la memoria in quanto se ne occupa direttamente .NET, ma se la DLL dovesse essere utilizzata da altri, ad esempio un'applicazione C++, allora è necessario effettuare in modo esplicito la deallocazione con CoTaskMemFree().

    Non mi dilungo oltre, ma spero di averti chiarito il dubbio. Per dettagli sui vari metodi di allocazione puoi leggere questa pagina MSDN: http://msdn.microsoft.com/en-us/libr...sktop/aa366533(v=vs.85).aspx


  5. #5
    Utente di HTML.it
    Registrato dal
    Jun 2010
    Messaggi
    250
    Ah ecco...quindi in pratica si usa la suddetta funzione quando voglio allocare memoria che deve essere gestita sia dalla dll stessa che dal .Net (in questo caso),giusto?

    Comunque riguardo all'aggiunta della libreria non ho ben capito dove essa vada aggiunta...io utilizzo Codeblocks,sono andato in Build Options-->Linker Settings-->lì c'era una specie di tabella...il titolo della tabella è link libraries,e come voce ce n'è una unica che si chiama user 32.Io ho provato ad aggiungere IL FILE .A relativo alla libreria... in particolare si chiama libole32.a ,fatto sta che compilando mi ese scritto
    codice:
    You must select a host application to run a library...
    Sicuramente c'è qualcosa che non va e non ho ben capito dove aggiungere il file...un'ultima cosa...è normale che non riesca a trovare file con estensione *.lib ma solo dei *.a ??
    Scusa il disturbo eh . .

  6. #6
    Utente di HTML.it
    Registrato dal
    Jun 2010
    Messaggi
    250
    EDIT:
    Niente sono stato un ingenuo...infatti non mi ero accorto che la libreria si era già creata e devo solo fare la compilazione...io invece tentavo anche di mandare in esecuzione D:
    Comunque poi ritornando su visual c# mi si ripresenta sempre quel maledetto carattere invocando la funzione.
    Cosa c'è che non va stavolta?

  7. #7
    Utente di HTML.it
    Registrato dal
    Jun 2010
    Messaggi
    250

    [RISOLTO] [C#] Problema passaggio puntatori

    RIEDIT: Funziona finalmente!!!!

    Dovevo solo seguire più precisamente i tuoi post precedenti...grazie ancora,sei un genio!!
    Ti devo una birra

  8. #8
    Mi fa piacere esserti stato di aiuto!!!

    Attento che ti prendo in parola sul fatto della birra....




  9. #9
    Utente di HTML.it
    Registrato dal
    Jun 2010
    Messaggi
    250
    Attento che ti prendo in parola sul fatto della birra....
    Haha va bene

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.