Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » FAQ C / C++ (WinAPI, Konsole) » Systeminformationen ermitteln

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
18.03.2003, 18:28 Uhr
Bruder Leif
dances with systems
(Operator)


Ein kleines Beispielprogramm für alle, die unter Windoof Daten über das System abfragen wollen. Sollte eigentlich alles selbsterklärend sein, das Programm fragt den Prozessortyp und Taktfrequenz, Speichergröße, Computername, OS, Laufwerke und die installierten Drucker ab. Wenn noch was unklar ist, schreib ich vielleicht auch mal nen längeren Text dazu... *g*


C++:
// Die Assembler-Teile müssen ggf. compilerspezifisch angepasst werden...
#define CPUID DB 0x0F, 0xA2
#define RDTSC DB 0x0F, 0x31

//##############################################################################

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <windows.h>

using namespace std;

//##############################################################################

long GetCpuSpeed(void)
{
    SYSTEM_INFO SysInf;
    DWORD start_high, start_low, overhead_high, overhead_low, MHz;

    GetSystemInfo(&SysInf);
    if(SysInf.wProcessorLevel<5) return 0;  // RDTSC gibts erst ab Pentium!

    MHz = 100000;

    _asm
    {
        RDTSC
        MOV overhead_low, EAX
        MOV overhead_high, EDX
        RDTSC
        SUB EAX, overhead_low
        SBB EDX, overhead_high
        MOV overhead_low, EAX
        MOV overhead_high, EDX
        RDTSC
        MOV start_low, EAX
        MOV start_high, EDX
    }
    Sleep(100);
    _asm
    {
        RDTSC
        SUB EAX, overhead_low
        SBB EDX, overhead_high
        SUB EAX, start_low
        SBB EDX, start_high
        DIV MHz
        MOV MHz, EAX
    }
    return MHz;  
}

//##############################################################################

void System()
{
    OSVERSIONINFO VersInf;
    DWORD dwEAX, dwEBX, dwECX, dwEDX, dwBuffer = 511;
    WORD wTyp, wFamilie, wModell;
    char szBuffer[512], szVendor[16];
    MEMORYSTATUS MemState;
    HDC hdcDesktop;
    int iCpuSpeed;

    cout << "[System]" << endl;

    cout << "OS                   ";
    VersInf.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);  
    GetVersionEx(&VersInf);

    if(VersInf.dwPlatformId == VER_PLATFORM_WIN32_NT)
    {
        if(VersInf.dwMajorVersion == 5)
        {
            if(VersInf.dwMinorVersion == 0) cout << "Windows 2000";
            if(VersInf.dwMinorVersion == 1) cout << "Windows XP";
        }
        else cout << "Windows NT";
    }
    else
    if(VersInf.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
    {
        cout << "Windows 95/98/ME";
    }

    cout << " " << VersInf.dwMajorVersion << "." << VersInf.dwMinorVersion << "." << VersInf.dwBuildNumber;
    cout << " " << VersInf.szCSDVersion << endl;

    cout << "CPU                  ";

    _asm
    {
        XOR EAX, EAX
        CPUID
        MOV dwEBX, EBX
        MOV dwECX, ECX
        MOV dwEDX, EDX
        MOV EAX, 1
        CPUID
        MOV dwEAX, EAX
    }

    szVendor[0]  = LOBYTE(LOWORD(dwEBX)); szVendor[1]  = HIBYTE(LOWORD(dwEBX));
    szVendor[2]  = LOBYTE(HIWORD(dwEBX)); szVendor[3]  = HIBYTE(HIWORD(dwEBX));
    szVendor[4]  = LOBYTE(LOWORD(dwEDX)); szVendor[5]  = HIBYTE(LOWORD(dwEDX));
    szVendor[6]  = LOBYTE(HIWORD(dwEDX)); szVendor[7]  = HIBYTE(HIWORD(dwEDX));
    szVendor[8]  = LOBYTE(LOWORD(dwECX)); szVendor[9]  = HIBYTE(LOWORD(dwECX));
    szVendor[10] = LOBYTE(HIWORD(dwECX)); szVendor[11] = HIBYTE(HIWORD(dwECX));
    szVendor[12] = 0x00;
    cout << szVendor;

    wTyp = (dwEAX >> 12) & 3;
    wFamilie = (dwEAX >> 8) & 15;
    wModell = (dwEAX >> 4) & 15;

    if(!strcmp(szVendor, "GenuineIntel"))
    {
        char szTyp[4][16]={"", " Overdrive", "Dual"};
        char szFam5[16][32]={"P5 Prototyp", "Pentium", "Pentium", "Pentium (486 OD)", "Pentium MMX"};
        char szFam6[16][16]={"P6 Prototyp", "Pentium Pro", "", "Pentium II", "", "Pentium II", "Celeron A", "Pentium III", "Pentium III", "", "Xeon"};
        cout << " ";

        switch(wFamilie)
        {
            case 4:  cout << "80486"; break;
            case 5:  cout << szFam5[wModell]; break;
            case 6:  cout << szFam6[wModell]; break;
            case 15: if(wModell == 0) cout << "Pentium 4"; break;
        }
        cout << szTyp[wTyp];
    }
    else
    if(!strcmp(szVendor, "AuthenticAMD"))
    {
        char szFam5[16][8]={"K5/M0", "K5/M1", "K5/M2", "K5/M3", "", "", "K6/M6", "K6/M7", "K6-2", "K6-3"};
        char szFam6[16][32]={"", "Athlon/M1", "Athlon/M2", "Duron/M3", "Athlon/M4", "", "Athlon MP/XP/Duron, M6", "Duron/M7"};
        cout << " ";

        switch(wFamilie)
        {
            case 4:    if(wModell > 13) cout << "5x86"; else cout << "486"; break;
            case 5:    cout << szFam5[wModell]; break;
            case 6:    cout << szFam6[wModell]; break;
        }
    }

    cout << " (TFM " << wTyp << "/" << wFamilie << "/" << wModell << ")";

    // GetCpuSpeed gibt erst ab dem 2. Aufruf den richtigen Wert zurück, warum auch immer...
    GetCpuSpeed();
    iCpuSpeed = GetCpuSpeed();
    if(iCpuSpeed < 1000) sprintf(szBuffer, ", %d MHz", iCpuSpeed);
    else sprintf(szBuffer, ", %.1f GHz", (float) iCpuSpeed / 1000);
    cout << szBuffer << endl;

// Geht unter Windows nicht wg. Protected Mode
//    cout << "BIOS-Name:      "; try { cout << ((char*) 0xFE061) << endl; } catch(...) { cout << "n/a" << endl; }
//    cout << "BIOS-Copyright: "; try { cout << ((char*) 0xFE091) << endl; } catch(...) { cout << "n/a" << endl; }
//    cout << "BIOS-Datum:     "; try { cout << ((char*) 0xFFFF5) << endl; } catch(...) { cout << "n/a" << endl; }
//    cout << "BIOS-Seriennr:  "; try { cout << ((char*) 0xFEC71) << endl; } catch(...) { cout << "n/a" << endl; }

    cout << "Computername         ";
    GetComputerName(szBuffer, &dwBuffer);
    cout << szBuffer << endl;

    MemState.dwLength = sizeof(MEMORYSTATUS);
    GlobalMemoryStatus(&MemState);
    cout << "RAM                  ";
    cout << (int) (MemState.dwTotalPhys / 1048576 + 1) << " MB" << endl;
    cout << "Auslagerungsdatei    ";
    cout << (int) (MemState.dwTotalPageFile / 1048576 + 1) << " MB" << endl;

    cout << "Bildschirmaufloesung ";
    cout << GetSystemMetrics(SM_CXSCREEN) << " * " << GetSystemMetrics(SM_CYSCREEN) << endl;

    cout << "Farbtiefe            ";
    hdcDesktop = GetDC(0);
    cout << GetDeviceCaps(hdcDesktop, BITSPIXEL) << " Bits/Pixel" << endl;
    ReleaseDC(0, hdcDesktop);
}

//##############################################################################

void Laufwerke()
{
    DWORD dwDrives = GetLogicalDrives();
    ULARGE_INTEGER nDummy, nTotalBytes, nFreeBytes;
    int iBytes;
    char szDrive[8]="A:\\";
    char szVolName[80], szFSName[80], szBuffer[80];
    bool bQueryVol;

    cout << "[Laufwerke]" << endl;

    for(int i=0, j=1; i<26; i++, j*=2)
    {
        if(dwDrives & j)
        {
            szDrive[0] = i + 'A';
            cout << szDrive << "                  ";
            bQueryVol = false;

            switch(GetDriveType(szDrive))
            {
                case DRIVE_UNKNOWN:     cout << "Unbekannt"; break;
                case DRIVE_NO_ROOT_DIR: cout << "? Kein Root-Verzeichnis ?"; break;
                case DRIVE_REMOVABLE:   cout << "Wechseldatentraeger"; bQueryVol = true; break;
                case DRIVE_FIXED:       cout << "Festplatte"; bQueryVol = true; break;
                case DRIVE_REMOTE:      cout << "Netzwerkverknuepfung"; break;
                case DRIVE_CDROM:       cout << "CDROM"; break;
                case DRIVE_RAMDISK:     cout << "RAM-Disk"; bQueryVol = true; break;
            }

            if(bQueryVol)
            {
                if(GetDiskFreeSpaceEx(szDrive, &nDummy, &nTotalBytes, &nFreeBytes))
                {
                    iBytes = nTotalBytes.QuadPart/1048576;
                    if(iBytes < 1024) sprintf(szBuffer, ", %5d MB Kapazitaet", iBytes);
                    else sprintf(szBuffer, ", %5.1f GB Kapazitaet", (float) iBytes / 1024);
                    cout << szBuffer;

                    iBytes = nFreeBytes.QuadPart/1048576;
                    if(iBytes < 1024) sprintf(szBuffer, ", %5d MB frei", iBytes);
                    else sprintf(szBuffer, ", %5.1f GB frei", (float) iBytes / 1024);
                    cout << szBuffer;
                }

                if(GetVolumeInformation(szDrive, szVolName, 79, NULL, NULL, NULL, szFSName, 79))
                    cout << ", " << szFSName;
            }
            cout << endl;
        }
    }
}

//##############################################################################

void Drucker()
{
    PRINTER_INFO_1 paDrucker[32];
    DWORD dwDummy, dwCount, i;

    cout << "[Drucker, lokal]" << endl;
    EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 1, (unsigned char*) (&paDrucker[0]), sizeof(paDrucker), &dwDummy, &dwCount);

    for(i=0; i<dwCount; i++)
        cout << paDrucker[ i ].pName << endl;

    cout << endl << "[Drucker, Netzwerk]" << endl;
    EnumPrinters(PRINTER_ENUM_NETWORK, NULL, 1, (unsigned char*) (&paDrucker[0]), sizeof(paDrucker), &dwDummy, &dwCount);

    for(i=0; i<dwCount; i++)
        cout << paDrucker[ i ].pName << endl;
}

//##############################################################################

int main()
{
    SetErrorMode(SEM_FAILCRITICALERRORS);

    System();
    cout << endl;
    Laufwerke();
    cout << endl;
    Drucker();
    return 0;
}

//##############################################################################


--
Mit 40 Fieber sitzt man nicht mehr vor dem PC.
Man liegt im Bett.
Mit dem Notebook.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
19.03.2003, 18:14 Uhr
Christian
C/C++ Master
(Operator)


Hallo!

Ich würde das Programm gerne testen, hab aber keine Ahnung von Assembler (also wirklich NULL Ahnung). Ich habe auch keine Ahnung, wie ich die Compilereinstellungen noch verändern muss, dass ich keine Fehlermeldungen bekomme.
Ich erhalte mit meinem VC++ 6.0. den Fehler:

Compiler-Fehler C2400
Inline-Assembler: Syntaxfehler in 'Kontext'; 'Token' gefunden

Das angegebene Token verursachte einen Syntaxfehler innerhalb des angegebenen Kontextes.

Das Angeben einer Pentium-Anweisung kann diesen Fehler verursachen. Durch Wählen der Pentium-Option (/G5) erzeugt der Compiler Anweisungssequenzen, die für den Pentium optimiert sind, jedoch werden Pentium-spezifische Anweisungen nicht erzeugt.


Wer hilft??
--
Grüße, Christian
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
19.03.2003, 20:16 Uhr
Bruder Leif
dances with systems
(Operator)


Huuuuups... das kommt davon. Hab das ganze mit dem Borland-Compiler gebastelt, der von Microsoft schluckt das nicht so ohne weiteres.
Im Prinzip läuft es darauf hinaus, daß es das "DB"-Statement bei Microsoft nicht gibt. Dort heißt es "_emit", und verträgt immer nur ein Byte auf einmal, d.h. die defines bringen nix... Kochrezept:

1. Jedes CPUID wird durch diese zwei Zeilen ersetzt:

C++:
_emit 0x0f
_emit 0xa2



2. Jedes RDTSC wird durch diese zwei Zeilen ersetzt:

C++:
_emit 0x0f
_emit 0x31



3. Aus dem "_asm" wird "__asm", also je einen Unterstrich dazu


Dann sollte das funktionieren!
--
Mit 40 Fieber sitzt man nicht mehr vor dem PC.
Man liegt im Bett.
Mit dem Notebook.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
20.03.2003, 13:34 Uhr
Christian
C/C++ Master
(Operator)


Hi!

Nummer 3 musste ich gar nicht mehr ändern. :-)

Vielen Dank, es funktioniert jetzt.
Kann man in kurzen Worten erklären, was in den Assemblerbereichen denn eigentlich passiert?
--
Grüße, Christian
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
21.03.2003, 20:01 Uhr
Bruder Leif
dances with systems
(Operator)


Moin!

Aaaaaaalso: Der erste Block führt insgesamt dreimal den RDTSC-Befehl aus. Der wurde ab dem Pentium ins Silizium gegossen, und überträgt einen 64Bit-Wert aufgeteilt auf die beiden 32Bit-Register EAX und EDX. Der Wert entspricht dem "Clock Count", d.h. einem internen Zähler, der angibt, wie viele Takte seit dem Anschalten des Rechners vergangen sind. Diesen Wert sichern wir in zwei Variablen, und führen den Befehl gleich nochmal aus. Dadurch erhalten wir die Anzahl an Taktzyklen, die wir für das Speichern der Werte brauchen - eben den Overhead. Mit diesem Wissen ausgestattet, kommt ein drittes RDTSC, um den Taktzähler vor der folgenden Zwangspause von 100 ms auszulesen. Nach dieser Pause lesen wir im 2. Block den jetzigen Stand aus, führen eine 64Bit-Subtraktion durch, teilen den Wert auf verträgliches Niveau runter, und erhalten die ungefähre (!!!) Taktfrequenz in MHz (nur ungefähr, weil wir den Overhead der sleep-Funktion nicht kennen).
Der dritte Block führt den CPUID-Befehl aus, der uns Informationen über den Prozessor liefert. Nachdem das Programm für 32Bit-Windows geschrieben wurde, gehen wir einfach davon aus, daß der Prozessor den CPUID-Befehl unterstützt (auf den ganz alten Prozessoren läßt eh niemand freiwillig auch nur Win95 laufen...). Der Rückgabewert steht in den vier 32Bit-Registern EAX, EBX, ECX und EDX. In EAX steht dabei auf einzelne Bits verteilt der Typ, die Familie und das Modell des Prozessors, und daraus ermittelt der folgende C-Teil dessen Namen. Die Register EBX, ECX und EDX enthalten (vorsicht, endian) einen ASCII-String mit dem Namen des Herstellers, z.B. "GenuineIntel", "AuthenticAMD", "CyrixInstead" usw. Manche Prozessoren geben über CPUID auch gleich ihren Namen zurück, aber eben nicht alle - deshalb auf diese etwas aufwendigere Art...
--
Mit 40 Fieber sitzt man nicht mehr vor dem PC.
Man liegt im Bett.
Mit dem Notebook.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ FAQ C / C++ (WinAPI, Konsole) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: