Teile von SDK ins Programm reinladen (oder Teile von SDK beim Anwender installieren) und noch char* freigaben



  • Hallo liebe Helferlein,

    erstmal danke das Ihr ueberhaupt zu diesem Beitrag gekommen seid 🙂
    Ich versuche mein Problem so klein und verstaendlich wie nur moeglich zu formulieren. Also nicht von der Textmenge erschrecken 🙂

    Problem 1:
    Ich habe eine DLL in C++ geschrieben die so eine '.netmodule'-Datei verwendet. Auf dieser '.netmodule'-Datei greife ich mit Hilfe von .NET darauf zu.

    // Eine Funktion in der DLL
    extern "C" __declspec(dllexport) char* getName (int Id)
    {
      EinNamespace::EineKlasse ^cl = gcnew EinNamespace::EineKlasse();
      System::IntPtr pointer = System::Runtime::InteropServices::Marshal::StringToHGlobalAuto( cl->getName(Id) );
      char* temp = (char*)(void*)pointer;
    
      //Speicher freigeben
      delete cl;
      System::Runtime::InteropServices::Marshal::FreeHGlobal(pointer); //hier ist mein 2. Problem, werde ich spaeter erlaeutern
      return temp;
    }
    

    Zusammenfassung: Also, ich habe eine DLL die viele Funktionen hat. Diese Funktionen in der DLL, greifen auf eine '.netmodule'-Datei zu.
    Diese DLL verwende ich nun in ein anderes C++ Programm (Nennen wir das Programm 'aufrufDLL')

    Nun zu meinem Problem: aufrufDLL funktioniert nur auf meinem Rechner. Grund hierfuer ist das ich "Microsoft .NET Framework SDK (Software Development Kit) 2.0 (x86)" verwende.
    Ich habe das Problem auf ein zweit Rechner einkreisen koennen. Erlaeuterung:
    Ich habe eine 400KB grosse Datei von Microsoft gedownloaded, wo man sich das auswaehlen kann, was man installieren moechte. Ich bin jeden Punkt duchgegangen und nach jedem Installiertem Punkt habe ich das Programm aufrufDLL ausgefuehrt. Es hat zu diesem zeitpunkt funktioniert, als ich den "C++-Compiler" installiert habe. Nun habe ich die SetupSDK.exe erneut ausgefuehrt und die Punkte entfernt die ich nicht benoetige. Das Programm aufrufDLL funktioniert immer noch. Der "C++-Compiler" benoetigt rund 130MB. Wenn ich aber den Hacken beim "C++-Compiler" weg nehme, dann bekomme ich nur rund 90MB wieder. Das heisst ich habe SDK installiet ohne einen Punkt ausgewaehlt zu haben. Dennoch sind einige MB's vom Compiler auf dem Rechner uebrig geblieben.

    Wer sich das mit der SetupSDK.exe nicht vorstellen kann, hier ein Link.
    Man muss sich das nicht gleich installieren, aber man kann sich den Setup-Wizard anschauen.
    http://www.microsoft.com/downloads/details.aspx?familyid=4377f86d-c913-4b5c-b87e-ef72e5b4e065&displaylang=en

    Ich verwende "Microsoft Visual C++ 2005 Express Edition", ich habe aber auch "Microsoft Visual Studio .NET 2003". Ich habe Microsofts Framework 1.1 und 2 installiert. Auf dem zweit Rechner habe ich nur "Microsoft Visual Studio .NET 2003" installiert aber auch Microsofts Framework 1.1 und 2. Was ich nicht verstehe ist, wieso ich einen "C++-Compiler" brauche? Es ist unsinn SDK auf ein Anwender-Rechner zu installieren und wenn ich den Anwender sage: Du musst den "C++-Compiler" installieren, dann greift er sich an den Kopf.
    Aber eigentlich ist es ja nicht der "C++-Compiler" den man braucht, denn als ich im Nachhinein den Checkbox-Hacken vom "C++-Compiler" entferte, blieben ja noch viele MB's uebrig. Und genau diese (DLLs?) Dateien brauche ich. Aber ich habe nichts gefunden was ich auf dem Anwenderrechner installieren koennte, so wie .NET Framework 2 erweiterung oder so. Ich weiss auch nicht welche DLLs meine Anwendung braucht.
    Aus diesem Grund habe ich einen Loesungsvorschlag, wenn Ihr einen anderen habt sagt bitte Bescheid.
    Eigentlich ist es ja so, das die CLR-Anwender nur dieses so genannte Framework benoetigen. Aber die haben wie es aussieht nicht alles. Aus diesem Grund moechte ich alle noetigen DLL, LIB und was auch immer in die Anwendung laden. Wie mach ich das?
    Das war Problem 1. 😉

    Problem 2:
    Siehe Quellcode oben. Ich gebe als Rueckgabewert den char* temp zurueck. Der temp Zeiger zeigt aber auf pointer und der muss freigegeben werden. Denn das Mutterprogramm was die DLL benutzt, gibt diesen Zeiger nicht frei. So wie ich das momentan sehe, muss ich den Inhalt mit Hilfe von strcpy kopieren. Aber dann muss ich einen Buffer auserhalb der Funktion erstellen. Fuer eine Funktion mag das ja evtl. noch die Loesung sein, aber ich habe ja viele und die Funktion wird ja auch staendig aufgerufen.

    Zusammenfassung: Wenn ich den pointer nicht freigebe, dann habe ich auch meine Zeichenkette. Wenn ich aber die Funktion von meine aufrufDLL-Programm 2.000.000.000 mal aufrufe, dann ist der Arbeitsspeicher voll (1,6 GB locker, danach hab ich abgebrochen). Wenn ich aber den pointer freigebe, dann bekomme ich nur Datenmuell.
    Hab Ihr ein vorschlag hierfuer? Eventuell den char* in aufrufDLL freigeben, wenn er nicht mehr benoetigt wird (das ohne .net-Funktion). Aber wie?

    Ich danke jedem der sich Muehe gibt mir zu Helfen. Danke. Ich weiss das es eure Privatzeit ist und genau aus diesem Grund nehme ich den Hut ab. 👍
    Ich hoffe ich habe alles erwaehnt, sollte aber dennoch was fehler bzw. etwas nicht zu verstehen sein, dann sag mir bitte umgehend Bescheid. Damit die anderen das besser haben.

    Hochachtungsvoll
    euer h.peter

    PS: Man koennte den oben genannten Link auf dieser Seite hinzufuegen http://www.c-plusplus.net/forum/viewtopic-var-t-is-143003.html
    Aber natuerlich statt diesem Link: Microsoft® Windows® Software Development Kit (SDK) Update for Windows Vista
    Denn dieser Link ist nur fuer Vista, der Link oben ermittelt mit Hilfe von einem kleinen Tool eine Nummer die angibt welches Betriebssystem man hat und die muss man dann im Browser eingeben, wodurch man dann die passende SDKSetup.exe freigeschaltet bekommt.



  • Hallo.
    Hat denn keiner Ahnung davon?

    Waere schoen wenn es doch so waere.
    Danke.



  • Ich verstehe Dein 1. Problem nicht ganz... Warum willst Du das PSDK auf dem Zielrechner installieren???? Hab ich nicht kapiert...
    Installier einfach das .NET-Redistributabel 2.0 und das VC-Redistributable 2005-SP1:
    Microsoft .NET Framework 2.0 Redistributable (x86):
    http://www.microsoft.com/downloads/details.aspx?di ....... &FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5

    Microsoft Visual C++ 2005 SP1 Redistributable Package (x86):
    http://www.microsoft.com/downloads/details.aspx?fa ....... FD9-AE1A-4A14-984D-389C36F85647&displaylang=de

    Zum Problem 2:
    Du gibst einen *freigegebenen* Speicher zurück... das wird früher oder später zu einem Absturz führen!
    Einen "char*" zurückzugeben ist eigentlich schon ein verbrechen genug... bitte lass einen Buffer in die Funktion reingeben (und natürlich die max.-Länge die dieser Buffer hat), welcher die Daten entgegennimmt. Dann hast Du das Problem nicht.
    Bzgl. String-Konvertierung: siehe FAQ.



  • Hallo,

    zum 1. Problem:
    Ich moechte nicht SDK installieren.

    [...] Es ist unsinn SDK auf ein Anwender-Rechner zu installieren [...]

    Was ich brauche sind die DLLs usw.
    Entweder ins Programm reinladen oder die DLLs auf den Anwender-Rechner installieren.

    Ich habe schon sehr sehr viele Sachen installiert und getestet. "Microsoft .NET Framework 2.0 Redistributable (x86)" hab ich schon, "Microsoft Visual C++ 2005 SP1 Redistributable Package (x86)" habe ich glaub ich auch schon installiert. Momentan komm ich nicht auf den Rechner, erst am Montag wieder. Hab aber alle Programme und Quelltexte hier bei mir, aber irgendwie funktioniert das auf diesen dritten Testrechner. Am Montag kann ich ganz genau sagen ob das SP1 geholfen hat oder nicht.

    2. Problem:

    // Eine Funktion in der DLL
    extern "C" __declspec(dllexport) int getVersion (int Id)
    {
      EinNamespace::EineKlasse ^cl = gcnew EinNamespace::EineKlasse();
      System::IntPtr pointer = System::Runtime::InteropServices::Marshal::StringToHGlobalAuto( cl->getVersion(Id) );
      char* temp = (char*)(void*)pointer;
    
      int tmp2 = atoi(temp);
    
      //Speicher freigeben
      delete cl;
      System::Runtime::InteropServices::Marshal::FreeHGlobal(pointer);
    
      return tmp2;
    }
    

    Es hat absolut nichts mit dem Datentyp zu tun. Diese Funktion hat int als Rueckgabetyp und dennoch wird der Speicher voll.
    Das Problem liegt daran das es ein Speicherbereich fuer die DLL existiert und ein Speicherbereich fuer die Anwendung aufrufDLL. Diese brauchen aber ein gemeinsamen Speicherbereich und darueber zu Kommunizieren. Und hier liegt doch das Problem. Wie es aussieht wird der Rueckgabewert im gemeinsamen Speicher geschrieben. Die Anwendung aufrufDLL kopiert sich das ganze heraus. Wer gibt aber den Speicher vom int (Rueckgabewert ) jetzt zurueck?
    Also irgendwie liegt hier das Problem: Die Kommunikation zwischen aufrufDLL und der DLL.
    Ich wiederhole, es hat also nichts mit dem Rueckgabetyp zu tun!
    Die oben genannte Funktion funktioniert auch nicht! Ich habe es getestet.
    Danke fuer die Hilfe. Ich hoffe du verstehst das ganze.
    Ein weiteres schoenes Wochenende.



  • Anhand der von Dir gezeigten Methode kann der Speicher nicht steigen... es muss eine andere Ursache haben...



  • Hallo,

    ich kommentiere immer alles heraus und lass nur eine Funktion uebrig. Wenn ich diese Funktion (die letzte) in eine void-Rueckgabetyp-Funktion aendere, dann steigt der Speicher nicht. Wenn ich das aber wieder in int umaendere dann steigt der Speicher wieder.
    Wie gesagt, das Problem liegt irgendwo hier.

    Noch als Info. So rufe ich die Funktion auf. Jetzt mal egal mit was fuer Parameter. Und egal was fuer ein Rueckgabetyp, hier hab jetzt einfach mal int genommen.

    #include <windows.h>
    #include <iostream>
    #include "tchar.h"
    
    typedef int (*getVersion)(void);
    
    int main()
    {
        HINSTANCE DLL = LoadLibrary(_T("DLL.dll"));
    
        if(DLL)
        {
            for (int i = 0; i < 4000000000; i++)
            {
                getVersion temp3;
                temp3 = (getVersion)GetProcAddress(DLL, "getVersion");
                std::cout << temp3() /*<< "                        " << i */<< std::endl;
            }
        }
        return 0;
    }
    

    Hast du noch Ideen?
    Ich Danke so oder so fuer deine Hilfe. Gruesse.



  • Hat eigentlich hier kein anderer eine Idee?
    Gruesse.



  • Was macht die Funktion "getVersion" genau?

    Poste mal bitte ein *vollständiges* Beispiel und nicht immer nur ganz verschiedene Code-Schnipsel...



  • Ach komm schon.
    Ein wenig mitdenken waere schon hilfreich.

    Die Funktion findest du in den Post weiter oben.



  • Guten Morgen,

    ich habe jetzt mal dieses Package installiert:
    "Microsoft Visual C++ 2005 SP1 Redistributable Package (x86)" und dieses "Microsoft Visual C++ 2005 Redistributable Package (x86)" hat aber nichts gebracht.
    Noch weitere Ideen?

    Hochachtungsvoll
    h.peter



  • h.peter schrieb:

    Ach komm schon.
    Ein wenig mitdenken waere schon hilfreich.

    Die Funktion findest du in den Post weiter oben.

    Du willst doch ne Lösung von uns haben, also liegt es an Dir, die Informationen so zu liefern das Dir jemand helfen will. Oder meinst Du, wir warten hier den ganzen Tag auf Posts weil die Kreuzworträtsel alle sind ?

    Was die "ich installiere dies und das" bringen soll weiß ich nicht. Du könntest die Zeit eher dafür verwenden, Dein Problem mal strukturiert zu Posten.
    Was EinNamespace::EineKlasse::getVersion(int) treibt ist aus Deinem Quellcode nicht zu erkennen. Man sieht ja nicht mal den Rückgabetyp. Den kann man bestenfalls erraten in dem reinterpretcast und Ansi C Funktionsgewirr.



  • Du willst doch ne Lösung von uns haben, also liegt es an Dir

    Ich habe es langsam so satt ... in jedem Forum gibt es irgend jemand der einfach nur blabla sagen kann. In manchen Foren soll man nicht alles doppelt posten und in machen

    also liegt es an Dir, die Informationen so zu liefern das Dir jemand helfen will

    Was soll daran so schlimm sein, jemand darauf hinzuweisen das der post oben schon die Antwort auf seine frage ist.

    Oder meinst Du, wir warten hier den ganzen Tag auf Posts weil die Kreuzworträtsel alle sind?

    Ich habe schon im ersten Post das hier gesagt:

    Ich danke jedem der sich Muehe gibt mir zu Helfen. Danke. Ich weiss das es eure Privatzeit ist und genau aus diesem Grund nehme ich den Hut ab. 👍

    Waere nett wenn du alles lesen wuerdest. Wer natuerlich nur den letzten Post liest, bekommt das in den falschen Hals. Entschuldigung hierfuer.

    Was EinNamespace::EineKlasse::getVersion(int) treibt ist aus Deinem Quellcode nicht zu erkennen

    Bis du eigentlich ein Programmierer?

    Man sieht ja nicht mal den Rückgabetyp

    Versteh ich nicht. Wo sieht man den Rueckgabetyp nicht.
    In dieser Zeile hier:
    extern "C" __declspec(dllexport) int getVersion (int Id)
    seh ich ein Rueckgabetyp. Wenn du kein siehst, dann kannst du mir auch nicht weiterhelfen.

    Wer das in den falschen Hals bekommt: Entschuldigung. Meine restlichen Beitraege sind meiner Meinung nach immer hoeflich gewesen und ich habe mich auch fast immer bedankt. Des weiteren habe ich am Anfang gesagt, das ich versuchen werde das so verstaendlich wie moeglich zu machen. Also hier nochmal:

    Ich habe hier eine Funktion in einer DLL:

    /////// Eine Funktion in der DLL //////////
    //Die Funktion liefert einen int-Wert zurueck. (Diesmal ohne Parameterannahme, damit es einfach einfach bleibt. :))
    
                               //Rueckgabetyp
    //Header der Funktion             |
    extern "C" __declspec(dllexport) int getVersion ()
    {
    
      //Ein Objekt erstellen, die Klasse liegt in einer '.netmodule'-Datei
      EinNamespace::EineKlasse ^cl = gcnew EinNamespace::EineKlasse();
    
      //einen Zeiger auf das Ergebnis des Funktionsaufrufes ueber das Objekt                 //Funktionsaufruf ueber das Objekt
      System::IntPtr pointer = System::Runtime::InteropServices::Marshal::StringToHGlobalAuto( cl->getVersion() );
    
      //Wir erstellen einen char-Zeiger und weisen auf die Position auf dem der pointer zeigt.
      char* temp = (char*)(void*)pointer;
    
      //das ganze wird in ein int umgewandelt
      int tmp2 = atoi(temp);
    
      ////// Speicher wird freigegeben //////
      //Der Speicherplatz des dynamisch erstelltem Objekts, wird freigegeben
      delete cl;
    
      //Der pointer muss auch freigegeben werden.
      System::Runtime::InteropServices::Marshal::FreeHGlobal(pointer);
    
      //Rueckgabe des int-wertes
      return tmp2;
    }
    

    Nun gibt es noch ein Projekt was das ganze aufruft.

    /////////// Hauptprogramm /////////////
    
    #include <windows.h>
    #include <iostream>
    #include "tchar.h"
    
    typedef int (*getVersion)(void);
    
    int main()
    {
        //DLL einbinden
        HINSTANCE DLL = LoadLibrary(_T("DLL.dll"));
    
        //wenn DLL auch da ist ...
        if(DLL)
        {
            //diese Schleife ist dafuer da, um zu ueberpruefen ob der Speicher voll wird oder nicht
            for (int i = 0; i < 4000000000; i++)
            {
                //variable fuer die entgegennahme des rueckgabetyps 
                getVersion temp3;
    
                //wie ein aufruf ueber eine DLL funktioniert erklaer ich jetzt nicht, @Knuddlbaer: sorry
                temp3 = (getVersion)GetProcAddress(DLL, "getVersion");
    
                //ausgabe des int-wertes und evtl. die schleifendurchlaeufe
                std::cout << temp3() /*<< "                        " << i */<< std::endl;
            }
        }
    
        //rueckgabewert fuer die main-funktion
        return 0;
    }
    

    Das Hauptprogramm hab ich euch erneut komplett zugesendet und in der DLL steht (wie schon gesagt) nur die eine Funktion (rest ist auskommentiert).

    Noch irgendwelche Fragen? Fragt einfach, wenn was sein sollte.
    Ich danke fuer jede Hilfe. Danke.
    Gruesse
    h.peter



  • extern "C" __declspec(dllexport) int getVersion ()
    {
    
      // Eine Managed Klasse erzeugen, über die mal rein garnichts bekannt ist,
      // Vorallem nicht, ob diese Klasse vllt. irgendwo etwas verwendet, das 
      // native Speicher reserviert	
      EinNamespace::EineKlasse ^cl = gcnew EinNamespace::EineKlasse();
    
      // Den unbekannten Rückgabetyp von cl->getVersion in einen nicht verwalteten Speicher kopieren. 
      // Ob dieser nun ANSI oder UNICODE sein wird, ist an dieser Stelle unbekannt.
      System::IntPtr pointer = System::Runtime::InteropServices::Marshal::StringToHGlobalAuto( cl->getVersion() );
    
      // Das Ergebnis mittels reinterpret_cast einfach in ein char* pointer murksen. 
      char* temp = (char*)(void*)pointer;
    
      //das ganze wird in ein int umgewandelt
      int tmp2 = atoi(temp);
    
      //Der Speicherplatz des dynamisch erstelltem Objekts, wird freigegeben
      delete cl;
    
      //Der pointer muss auch freigegeben werden.
      System::Runtime::InteropServices::Marshal::FreeHGlobal(pointer);
    
      //Rueckgabe des int-wertes
      return tmp2;
    } 
    
    // Das ganze wäre vllt. mein einem System::Int32::Parse einfacher zu lösen
    


  • h.peter schrieb:

    Ich habe es langsam so satt ... in jedem Forum gibt es irgend jemand der einfach nur blabla sagen kann.

    Stimmt. Manchmal ist ein aufstossen aber Notwendig. Was Du Postest ist einfach nur Chaos. Lies Dir Deine Beiträge hier in diesem Thread durch und überlege welche Informationen bereitgestellt wurden.

    Was soll daran so schlimm sein, jemand darauf hinzuweisen das der post oben schon die Antwort auf seine frage ist.

    Was ist daran so schlimm gefragt zu werden was der Rückgabewert einer Methode ist, die innerhalb der geposteten verwendet wird ?

    Waere nett wenn du alles lesen wuerdest. Wer natuerlich nur den letzten Post liest, bekommt das in den falschen Hals. Entschuldigung hierfuer.

    Dito - würdest Du lesen können, hättest Du bereits viele wertvolle Tips aufgeschnappt. Du kannst aber gerne weiterhin einfach Sinnlos Installationspakete auf den Rechnern laufen lassen.

    Was EinNamespace::EineKlasse::getVersion(int) treibt ist aus Deinem Quellcode nicht zu erkennen

    Bis du eigentlich ein Programmierer?

    Wann ist man denn Programmierer ? Meine Kentnisse reichen aus um zu erkennen, das für EinNamespace::EineKlasse::getVersion keine Signatur gepostet wurde.

    In dieser Zeile hier:
    extern "C" __declspec(dllexport) int getVersion (int Id)
    seh ich ein Rueckgabetyp. Wenn du kein siehst, dann kannst du mir auch nicht weiterhelfen.

    Reichen Deine Kentnisse um den Zusammehnang zwischen

    EinNamespace::EineKlasse::getVersion
    

    ,

    extern "C" __declspec(dllexport) int getVersion ()
    

    und

    Was EinNamespace::EineKlasse::getVersion(int) treibt ist aus Deinem Quellcode nicht zu erkennen. Man sieht ja nicht mal den Rückgabetyp.

    zu erkennen ?



  • Hallo,

    ich habe hier jetzt mal den noetigen Quelltext von der '.netmodule'-Datei besorgt.

    using System.Text;
    using System.Runtime.InteropServices;
    using System;
    
    namespace EinNamespace
    {
    
    	public class EineKlasse  : IDisposable
    	{
    
    		[DllImport("API.dll")]
    		private static extern int getVersion();
    
    		public string getDLLVersion()
    		{
    			return getStrFromPtr(getVersion());
    		}
            }
    
    }
    

    Danke und Gruesse


Anmelden zum Antworten