Dll

di Anonimizzato28877 il
15 risposte
Salve,

con la premessa di non essere esperto in C++, vi espongo il mio problema, ho la necessità di creare una dll in c++ con all'interno delle funzioni di utility, quale, ad esempio, la lettura del seriale dell'HD, la dll deve essere richiamata da un'applicazione C#, la funzione mi deve restituire una stringa contenente il serial HD, il codice della dll è questo:

__declspec(dllexport) char* __stdcall GetHd()
    {
        WmiQueryResult res;
        res = getWmiQueryResult(L"SELECT SerialNumber FROM Win32_PhysicalMedia", L"SerialNumber");
        if (res.Error != WmiQueryError::None) {
            return NULL;
        }
        std::string strValue;
        char* pszReturn = NULL;
        for (const auto& item : res.ResultList) {
            strValue.assign(item.begin(), item.end());
            ULONG ulSize = strlen(strValue.c_str()) + sizeof(char);
            pszReturn = (char*)::CoTaskMemAlloc(ulSize);
            strcpy(pszReturn, strValue.c_str());
            break;
        }
        return pszReturn;

    }
nall'applicazione C#, linko e chiamo la funzione in questo modo:

	[DllImport("util.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
        [return: MarshalAs(UnmanagedType.LPStr)]
        public static extern string GetHd();
        
        ...
        
        string serialhd = GetHd();
        

La funzione GetHd() mi restituisce NULL, lo stesso codice testato in un'applicazione console C++, funziona bene.


Grazie

15 Risposte

  • Ci dai il sorgente c++ funzionante?
  • oregon ha scritto:


    Ci dai il sorgente c++ funzionante?
    Eccolo

  • gian82 ha scritto:


    Prova a vedere l'esempio 2 , https://docs.microsoft.com/it-it/dotnet/csharp/language-reference/keywords/extern

    visto, il punto è che se scrivo una funzione di test che mi restituisce una semplice stringa, funziona regolarmente
    
    __declspec(dllexport) char* __stdcall Test()
        {
            char szSampleString[] = "StringaDiTest";
            ULONG ulSize = strlen(szSampleString) + sizeof(char);
            char* pszReturn = NULL;
            pszReturn = (char*)::CoTaskMemAlloc(ulSize);
            strcpy(pszReturn, szSampleString);
            return pszReturn;
        }
    
    questa funzione di test chiamata da C# funziona
    
    [DllImport("util.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
            [return: MarshalAs(UnmanagedType.LPStr)]
            public static extern string Test();
            
            string miotest = Test();
            
    
  • Puoi mandare i due progetti (DLL e C#) per provare velocemente?
  • Al di la della esportazione della funzione, GetHd() è intrisecamente errata, nel senso che forzi una std::wstring a diventare una std::string senza nessuna conversione. Se il committente chiede specificatamente come tipo di ritorno un char* devi modificare così (anche se mi sembra strano dato che le stringhe C# sono native Unicode):
    
           ...
    
        const auto& item = *(res.ResultList.cbegin());
        size_t sz = WideCharToMultiByte(CP_ACP, 0, item.c_str(), (int)item.size(), 0, 0, 0,0);
        char* pszReturn = (char*) ::CoTaskMemAlloc(sz+1);
        if (!pszReturn) return nullptr;
        ZeroMemory(pszReturn, sz + 1);
        WideCharToMultiByte(CP_ACP, 0, item.c_str(), (int)item.size(), pszReturn, sz, 0, 0);
    
        return pszReturn;
    
        }
    
    Il for l'ho tolto per via del break interno che elabora solo la prima wstring del vector in WmiQueryResult.

    Ti consiglio anche di prevedere una routine per liberare la memoria lato DLL quando la la stringa ASCIIZ è stata copiata nella string del C#
  • oregon ha scritto:


    Puoi mandare i due progetti (DLL e C#) per provare velocemente?
    Dove posso inviarli?
  • shodan ha scritto:


    Al di la della esportazione della funzione, GetHd() è intrisecamente errata, nel senso che forzi una std::wstring a diventare una std::string senza nessuna conversione. Se il committente chiede specificatamente come tipo di ritorno un char* devi modificare così (anche se mi sembra strano dato che le stringhe C# sono native Unicode):
    
           ...
    
        const auto& item = *(res.ResultList.cbegin());
        size_t sz = WideCharToMultiByte(CP_ACP, 0, item.c_str(), (int)item.size(), 0, 0, 0,0);
        char* pszReturn = (char*) ::CoTaskMemAlloc(sz+1);
        if (!pszReturn) return nullptr;
        ZeroMemory(pszReturn, sz + 1);
        WideCharToMultiByte(CP_ACP, 0, item.c_str(), (int)item.size(), pszReturn, sz, 0, 0);
    
        return pszReturn;
    
        }
    
    Il for l'ho tolto per via del break interno che elabora solo la prima wstring del vector in WmiQueryResult.

    Ti consiglio anche di prevedere una routine per liberare la memoria lato DLL quando la la stringa ASCIIZ è stata copiata nella string del C#


    Ottengo lo stesso risultato, ovvero NULL
  • Posta qui il link di dropbox o un sito da cui scaricarli
Devi accedere o registrarti per scrivere nel forum
15 risposte