Thread overview
Shared Library: Why doesn't this work?
Sep 27, 2008
Benji Smith
Sep 27, 2008
torhu
Sep 27, 2008
Benji Smith
Sep 28, 2008
Bryan Power
Oct 02, 2008
Benji Smith
September 27, 2008
I'm trying to read the total amount of memory on a Windows system (using D 1.35 and Tango 0.99.7 on WinXP SP3) using tango.sys.SharedLib to load kerner32.dll.

Here's the code...

---------------------------------------------------------------------
module SystemMemoryTest;

import tango.io.Stdout;
import tango.sys.SharedLib;

alias uint DWORD;
alias ulong DWORDLONG;

struct MEMORYSTATUSEX
{
   DWORD dwLength;
   DWORD dwMemoryLoad;
   DWORDLONG ullTotalPhys;
   DWORDLONG ullAvailPhys;
   DWORDLONG ullTotalPageFile;
   DWORDLONG ullAvailPageFile;
   DWORDLONG ullTotalVirtual;
   DWORDLONG ullAvailVirtual;
   DWORDLONG ullAvailExtendedVirtual;
}

typedef void function(MEMORYSTATUSEX*) func_type;
func_type myFunction;

void main() {

   if (auto lib = SharedLib.load(`c:\windows\system32\kernel32.dll`)) {
      Stdout("Loaded library").newline;

      if (void* symbolAddress = lib.getSymbol("GlobalMemoryStatusEx")) {
         Stdout.formatln("Found symbol at 0x{:x}", symbolAddress);

         void** pMyFunction = cast(void**) &myFunction;
         *pMyFunction = symbolAddress;

         MEMORYSTATUSEX mem;
         myFunction(&mem);

         Stdout.formatln("total physical mem: {0}", mem.ullTotalPhys);
         Stdout.formatln("avail physical mem: {0}", mem.ullAvailPhys);
      }
      lib.unload();
   }
}
---------------------------------------------------------------------

I have no problem compiling or running that example, it just doesn't produce the correct results:

   Loaded library
   Found symbol at 0x7c81f97a
   total physical mem: 0
   avail physical mem: 0

On the other hand, I can use a function from the UserGdi module, and it works correctly...

---------------------------------------------------------------------
module SystemMemoryTest;

import tango.io.Stdout;
import tango.sys.win32.UserGdi : GlobalMemoryStatus;
import tango.sys.win32.Types : MEMORYSTATUS;

void main() {

   MEMORYSTATUS mem;
   GlobalMemoryStatus(&mem);

   Stdout.formatln("total physical mem: {0}", mem.dwTotalPhys);
   Stdout.formatln("avail physical mem: {0}", mem.dwAvailPhys);
}
---------------------------------------------------------------------

Works like a charm!

   total physical mem: 2078838784
   avail physical mem: 1008336896

The reason I don't just use this code (despite it being much more clean and nice looking :) is that it doesn't work for systems with more than 2GB of RAM. The "GlobalMemoryStatusEx", which will work for systems with effectively limitless RAM, function isn't in the UserGdi module (evidently, it doesn't exist on earlier win32 platforms like Windows 98).

I'd like to use the "GlobalMemoryStatusEx" where it exists, and fallback to using the "GlobalMemoryStatus" function in cases where it doesn't.

But I can't figure out how to get the shared lib functionality to work.

Any suggestions?

Thanks!

--benji
September 27, 2008
Benji Smith wrote:
> I'm trying to read the total amount of memory on a Windows system (using D 1.35 and Tango 0.99.7 on WinXP SP3) using tango.sys.SharedLib to load kerner32.dll.
> 
> Here's the code...
> 
> ---------------------------------------------------------------------
> module SystemMemoryTest;
> 
> import tango.io.Stdout;
> import tango.sys.SharedLib;
> 
> alias uint DWORD;
> alias ulong DWORDLONG;
> 
> struct MEMORYSTATUSEX
> {
>     DWORD dwLength;
>     DWORD dwMemoryLoad;
>     DWORDLONG ullTotalPhys;
>     DWORDLONG ullAvailPhys;
>     DWORDLONG ullTotalPageFile;
>     DWORDLONG ullAvailPageFile;
>     DWORDLONG ullTotalVirtual;
>     DWORDLONG ullAvailVirtual;
>     DWORDLONG ullAvailExtendedVirtual;
> }
> 
> typedef void function(MEMORYSTATUSEX*) func_type;
> func_type myFunction;
> 
> void main() {
> 
>     if (auto lib = SharedLib.load(`c:\windows\system32\kernel32.dll`)) {
>        Stdout("Loaded library").newline;
> 
>        if (void* symbolAddress = lib.getSymbol("GlobalMemoryStatusEx")) {
>           Stdout.formatln("Found symbol at 0x{:x}", symbolAddress);
> 
>           void** pMyFunction = cast(void**) &myFunction;
>           *pMyFunction = symbolAddress;
> 
>           MEMORYSTATUSEX mem;
>           myFunction(&mem);
> 
>           Stdout.formatln("total physical mem: {0}", mem.ullTotalPhys);
>           Stdout.formatln("avail physical mem: {0}", mem.ullAvailPhys);
>        }
>        lib.unload();
>     }
> }
> ---------------------------------------------------------------------

Here's one that works, important changes marked with XXX :)

----
module SystemMemoryTest;

import tango.io.Stdout;
import tango.sys.SharedLib;

alias uint DWORD;
alias ulong DWORDLONG;

struct MEMORYSTATUSEX
{
    DWORD dwLength;
    DWORD dwMemoryLoad;
    DWORDLONG ullTotalPhys;
    DWORDLONG ullAvailPhys;
    DWORDLONG ullTotalPageFile;
    DWORDLONG ullAvailPageFile;
    DWORDLONG ullTotalVirtual;
    DWORDLONG ullAvailVirtual;
    DWORDLONG ullAvailExtendedVirtual;
}

// XXX: need to be stdcall, ie. extern (Windows)
extern (Windows) typedef void function(MEMORYSTATUSEX*) func_type;

void main() {

    if (auto lib = SharedLib.load(`c:\windows\system32\kernel32.dll`)) {
       Stdout("Loaded library").newline;

       if (auto myFunction = cast(func_type)lib.getSymbol("GlobalMemoryStatusEx")) {
          Stdout.formatln("Found symbol at 0x{:x}", myFunction);

          MEMORYSTATUSEX mem;
          mem.dwLength = mem.sizeof;  // XXX
          myFunction(&mem);

          Stdout.formatln("total physical mem: {0}", mem.ullTotalPhys);
          Stdout.formatln("avail physical mem: {0}", mem.ullAvailPhys);
       }
       lib.unload();
    }
}
----
September 27, 2008
torhu wrote:
> Benji Smith wrote:
>> I'm trying to read the total amount of memory on a Windows system (using D 1.35 and Tango 0.99.7 on WinXP SP3) using tango.sys.SharedLib to load kerner32.dll.
>>
>> Here's the code...

You're my hero! Thank you so much!!!

--benji
September 28, 2008
Benji Smith wrote:
>    if (auto lib = SharedLib.load(`c:\windows\system32\kernel32.dll`)

Just a note on the Windows library loading routines:

You should never use the absolute path. The root drive is not guaranteed to be C:, nor is the system directory guaranteed to be "system32". On older systems it may just be "system". Internally, the API .load is calling (LoadLibraryA/W) will automatically search the default system directory of your system, therefore only .load("kernel32.dll") is required.
October 02, 2008
Bryan Power wrote:
> Benji Smith wrote:
>>    if (auto lib = SharedLib.load(`c:\windows\system32\kernel32.dll`)
> 
> Just a note on the Windows library loading routines:
> 
> You should never use the absolute path. The root drive is not guaranteed to be C:, nor is the system directory guaranteed to be "system32". On older systems it may just be "system". Internally, the API .load is calling (LoadLibraryA/W) will automatically search the default system directory of your system, therefore only .load("kernel32.dll") is required.

Aha. That's good to know.

I was only using the absolute path for this little example. My actual code was going through its own system of tests to find the system directory. That was a waste!

Thanks!

--benji