AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

DllCall. Help, anyone?
Goto page 1, 2  Next
 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help
View previous topic :: View next topic  
Author Message
Veovis



Joined: 13 Feb 2006
Posts: 390
Location: Utah

PostPosted: Tue Jun 20, 2006 4:55 am    Post subject: DllCall. Help, anyone? Reply with quote

I guess that i dont really have a specific question, mostly just a general how do you use dllcall?

I've read the help files, searched msdn, looked at example scripts, and searched the forum. Still pretty mystified.

I get that dlls are Dynamic Link Librarys. Full of fun code to execute Twisted Evil Laughing . But what is a type and arg????

is type the type (i get double and uint and blah) that you are passing into the function with arg?
or is type the type of output you want from the dll with parameter arg?

And how do i even get a list of whats inside of a dll? is there some kind of dllcall("/?","HELP ME!!!") ????

Please someone enlighten me. I see great potential with dlls and i really want to learn to use them. Sorry to bother you, if anything, please just give me some links or something. Im really confused.
_________________

"Power can be given overnight, but responsibility must be taught. Long years go into its making."
Back to top
View user's profile Send private message Send e-mail Visit poster's website
PhiLho



Joined: 27 Dec 2005
Posts: 6721
Location: France (near Paris)

PostPosted: Tue Jun 20, 2006 10:34 am    Post subject: Reply with quote

A vast subject.

If you don't have a base knowledge of C (C++) or similar languages (Pascal...), you will have trouble to understand all the concepts...

I will try to explain the bases concisely... I will skip some finer points (like C functions with variable number of arguments), to avoid diluting the concepts...

In C (and lot of languages), variables have a type: they can be numerical (integer or floating number), a single character or a whole string (ended with a zero byte), or a pointer (a kind of reference).

Integer variables can have various sizes: byte or char (8bit), short (16bit), long (32bits), very long (Smile non standard name: 64bit). This is to allow to make a balance between the memory they use (an array of chars is much smaller than an array of longs) and the values they can hold (from 256 values up to several billions).

That's what is called the type of a variable.
In AHK, the same variable can hold integers, floating numbers, strings, binary blob... In C, the base language of the WinAPI, variables are strongly typed, you cannot store a string in variable declared as integer.

DLLs are collections of C functions.
A C function must be called with a fixed number of parameters, each parameter have a precise type.
For example, if I write:
Code:
hDC := DllCall("CreateDC", "Str", "DISPLAY", "UInt", 0, "UInt", 0, "UInt", 0)
colorBGR := DllCall("GetPixel", "UInt", hDC, "Int", x + offsetX, "Int", y + offsetY)
DllCall("DeleteDC", "UInt", hDC)
I call three different functions with various parameters (or arguments, if you prefer). For CreateDC, the first parameter is a string, the next three are integers. That's the expected types in input.
The function returns an integer (the default type, the most common one), that's the output type.

Veovis wrote:
And how do i even get a list of whats inside of a dll?
The only reliable way is to use the provided documentation. MSDN for the WinAPI, the doc. coming with the library for 3rd party DLLs.

I suggest you are looking for an easy Windows programming tutorial to get the basis you need if you want to explore this field further.

Don't hesitate to ask more (precise) questions, I will try to help.
_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Last edited by PhiLho on Tue Jun 20, 2006 12:16 pm; edited 1 time in total
Back to top
View user's profile Send private message Visit poster's website
Areilius



Joined: 16 Feb 2006
Posts: 42

PostPosted: Tue Jun 20, 2006 11:45 am    Post subject: Reply with quote

I don't know a whole lot about it myself, but I'll try to get you started.

As an example I'll show you how to call the MessageBox function.
The MSDN documentation gives the syntax/param order:
Code:
int MessageBox(
  HWND hWnd,
  LPCTSTR lpText,
  LPCTSTR lpCaption,
  UINT uType
);


The capital words like UINT are the param types.
Handles (such as HWND) are usually unsigned integers (Uint).
LPCTSTR means (I think) a pointer to a string (I wont go in to pointers), but using the "Str" type usually works anyway for some reason.

I don't really know what else to say... Just look at the syntax above, then at the equivilent DllCall below, and try to make the connections. If theres something you don't understand, just ask Smile
Code:
DllCall("MessageBox"                 ; Name of the function
   ,"Uint",0                         ; Handle of owner window, 0 means no owner.
   ,"Str","This is some text."       ; Message box text
   ,"Str","Title!"                   ; Message box title
   ,"Uint",0)                        ; Options


As for finding functions in a DLL, you can use Dependency Walker. It will only give you the function names, which isn't terribly useful alone.
Back to top
View user's profile Send private message Send e-mail
Veovis



Joined: 13 Feb 2006
Posts: 390
Location: Utah

PostPosted: Tue Jun 20, 2006 4:09 pm    Post subject: Reply with quote

Thankyou for your replies. PhiLho that helped alot. So (obvisouly) DllCall is a function, just everyother parameter is just declaring what the next parameter is.

Thanks Areilius that comparison helped alot too. I will look into the links and programs you provided.

One more (probably stupid question) is this:

Laszlo had some code that retreives the memory usage via a Kernal32.dll\GlobalMemoryStatus call.

Code:
DllCall("kernel32.dll\GlobalMemoryStatus", "uint",&memorystatus)
mem:=*(&memorystatus+4) ; LS byte is enough, mem = 0..100


from what i understand, hes just calling the function GlobalMemoryStatus, with the parameter "&memorystatus" that is declared as an unsigned int. (wiat, should &memorystatus be in qoutes?) And i looked up globalmemorystatus in msdn here
and found things such as availphys and totalpagefile and stuff so i tried passing those into my dll call like so
Code:
DllCall("kernel32.dll\GlobalMemoryStatus"
       ,"uint",&memoryusage
       ,"uint",&availphys
       ,"unit",&totalpagefile)

msgbox % &memoryusage
msgbox % &availphys
msgbox % &totalpagefile


and all three messageboxes say
Quote:
4673068


I have 392 ish megs of RAM but what is 4.6 million have to do with anything? And why do all three of the args that i passed return the same? or am i doing something wrong?
_________________

"Power can be given overnight, but responsibility must be taught. Long years go into its making."
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Veovis



Joined: 13 Feb 2006
Posts: 390
Location: Utah

PostPosted: Tue Jun 20, 2006 4:16 pm    Post subject: Reply with quote

okay basically what im trying to do is for my SysInfo script i want to be able to retreive someones total RAM and how much they are using so i can display something like "315/392 mg" or maybe a percent would be better anyways, but i figured i have to learn dlls eventually why not right now? So what do i have to pass into the function to get the "availphys" and "totalphys" (i think) values?
_________________

"Power can be given overnight, but responsibility must be taught. Long years go into its making."
Back to top
View user's profile Send private message Send e-mail Visit poster's website
BoBo
Guest





PostPosted: Tue Jun 20, 2006 4:25 pm    Post subject: Reply with quote

@ Veovis
I think that issue has been solved already as I've requested something similar in the past. I might be wrong but I think shimanov (btw. is he still with us?) has provided a working code snippet.

Search term: memory, capacity (?)
Back to top
BoBo
Guest





PostPosted: Tue Jun 20, 2006 4:30 pm    Post subject: Reply with quote

[Here] we go! Laszlo, shimanov & friends - a bunch o geniuses supported me on that Wink
Back to top
Veovis



Joined: 13 Feb 2006
Posts: 390
Location: Utah

PostPosted: Tue Jun 20, 2006 4:38 pm    Post subject: Reply with quote

Yep i found it at about the same time you did.
for processor
for memory

that is excactly what i wanted!
_________________

"Power can be given overnight, but responsibility must be taught. Long years go into its making."
Back to top
View user's profile Send private message Send e-mail Visit poster's website
PhiLho



Joined: 27 Dec 2005
Posts: 6721
Location: France (near Paris)

PostPosted: Tue Jun 20, 2006 4:46 pm    Post subject: Reply with quote

Awh, you are out of luck, you took a "magical" example that works because Laszlo knows how bytes are physically ordered in memory, so he uses a bad trick to lazily avoid to manage such structure.
I won't even try to explain it for you, it is a bit of advanced stuff (no offence intended! Smile), plus I don't find it is such a good idea because Windows will write stuff in the memory after the variable storage (unless he did a VarSetCapacity that you omitted. I won't search the original post...).

Anyway, if that's the precise DllCall that you need to be working, I can take a look.
Code:
/*
typedef struct _MEMORYSTATUS {
  DWORD dwLength;
  DWORD dwMemoryLoad;
  SIZE_T dwTotalPhys;
  SIZE_T dwAvailPhys;
  SIZE_T dwTotalPageFile;
  SIZE_T dwAvailPageFile;
  SIZE_T dwTotalVirtual;
  SIZE_T dwAvailVirtual;
} MEMORYSTATUS,
 *LPMEMORYSTATUS;

dwLength
    The size of the MEMORYSTATUS data structure, in bytes. You do not need to set this member before calling the GlobalMemoryStatus function; the function sets it.
dwMemoryLoad
    A number between 0 and 100 that specifies the approximate percentage of physical memory that is in use (0 indicates no memory use and 100 indicates full memory use).
        Windows NT:  Percentage of approximately the last 1000 pages of physical memory that is in use.
dwTotalPhys
    The total size of physical memory, in bytes.
dwAvailPhys
    The size of physical memory available, in bytes.
dwTotalPageFile
    The size of the committed memory limit, in bytes.
dwAvailPageFile
    The size of available memory to commit, in bytes.
dwTotalVirtual
    The total size of the user mode portion of the virtual address space of the calling process, in bytes.
dwAvailVirtual
    The size of unreserved and uncommitted memory in the user mode portion of the virtual address space of the calling process, in bytes.

All these types are 32bit long, so the structure is 8*4=32 bytes long.
*/

VarSetCapacity(memoryStatusBuffer, 32, 0)


/*
void GlobalMemoryStatus(
  LPMEMORYSTATUS lpBuffer
);
We have a pointer to a structure (or buffer). It is an integer, we give it the address of our variable.
In a DllCall, past the first parameter, we alternate types and expressions, so quotes around the third param!
*/

DllCall("GlobalMemoryStatus", "UInt", &memoryStatusBuffer)


/*
Now, we need to retreive the values in the structure.
I like to use the simple following function, but you can use the ExtractInteger described in the DllCall manual page.
*/

GetNextUInt(ByRef @struct, _bReset=false)
{
   local addr
   static $offset

   If (_bReset)
   {
      $offset := 0
   }
   addr := &@struct + $offset
   $offset += 4

   Return *addr + (*(addr + 1) << 8) +  (*(addr + 2) << 16) + (*(addr + 3) << 24)
}

skip := GetNextUInt(memoryStatusBuffer)
memoryLoad := GetNextUInt(memoryStatusBuffer)
totalPhys := GetNextUInt(memoryStatusBuffer)
AvailPhys := GetNextUInt(memoryStatusBuffer)
; etc.
MsgBox,
(
Memory load: %memoryLoad%`%
Total size of physical memory: %totalPhys% bytes
Size of physical memory available: %AvailPhys% bytes
)

_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")
Back to top
View user's profile Send private message Visit poster's website
Veovis



Joined: 13 Feb 2006
Posts: 390
Location: Utah

PostPosted: Wed Jun 21, 2006 3:14 am    Post subject: Reply with quote

PhiLho wrote:
I won't even try to explain it for you, it is a bit of advanced stuff


No please try.

Tell me if im right but i think its something like

(oh wow that code is pretty foreign... but ill try anyways)

so theres like a string (binary for example)

10001110100111000101100 (which evals to 4.6 million in normal decimal)

so are like the first 8 bits one value and the next 8 something else?
_________________

"Power can be given overnight, but responsibility must be taught. Long years go into its making."
Back to top
View user's profile Send private message Send e-mail Visit poster's website
PhiLho



Joined: 27 Dec 2005
Posts: 6721
Location: France (near Paris)

PostPosted: Wed Jun 21, 2006 9:08 am    Post subject: Reply with quote

OK, you asked for it, but I have to switch from "intuitive" mode to "analytic" mode...
I don't know where you had this code, but I found something similar, and indeed, there is NO memory overwriting as memoryStatus is largely oversized:
Laszlo's code wrote:
VarSetCapacity( memorystatus, 100 )
; [...]
DllCall("kernel32.dll\GlobalMemoryStatus", "uint",&memorystatus)
mem:=*(&memorystatus+4) ; LS byte is enough, mem = 0..100

So the DllCall fills this buffer as expected, and as shown in my previous message, the first two fields are 32bit long.
&memoryStatus gives the address in memory of the buffer. So it is a kind of pointer. &memorystatus+4 skips the first field (4 bytes) so points to the second field. *(&memorystatus+4) retrieves the byte pointed to. Since we are on a little-endian processor, the least signifying byte (LSB) is stored at this address. Since the value is always below 256, fetching just this byte is enough.
That's the trick, and of course it won't work for other values, hence the necessity for a function to fetch the bytes and stitch them together.
_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")
Back to top
View user's profile Send private message Visit poster's website
Veovis



Joined: 13 Feb 2006
Posts: 390
Location: Utah

PostPosted: Wed Jun 21, 2006 4:53 pm    Post subject: Reply with quote

ahhhhh that makes much more sense. the statement "LS byte is enough, mem = 0..100" finally makes sense since a byte can be 255, we never need more than a byte.

at first i was confused by all the & signs and mem:=*(&memorystatus+4). At first I thought it had something to do with C or DLLs but i got smart and and looked up expressions in the help files and figured out what the 4.6 million was that i was getting earlier. Its an address. everything makes more sense now. Thank You!
_________________

"Power can be given overnight, but responsibility must be taught. Long years go into its making."
Back to top
View user's profile Send private message Send e-mail Visit poster's website
olfen



Joined: 04 Jun 2005
Posts: 99
Location: Stuttgart, Germany

PostPosted: Wed Jun 21, 2006 6:12 pm    Post subject: Reply with quote

WinHex helped me get started with DllCalls and I am still using it to see what actually is happening in the process memory.
It allows you to open the memory of your running ahk script (Alt-F9) and see what data is present at a certain offset (you can get that offset by evaluating &variable).
Back to top
View user's profile Send private message Visit poster's website
sosaited as Guest
Guest





PostPosted: Sun Jun 25, 2006 12:57 pm    Post subject: Reply with quote

I have a very "annoying" question about DLLCALLS... I posted this question on MSDN forum too (3 Months) ago, but no one replied Mad

In most of the cases, MSDN states the FLAG (or similar) which are in Text format. But If I use them with the type "str" and the literal text, they wont work. For Example, in AHK's help file under Gui, ListvView Example:

Code:
if not DllCall("Shell32\SHGetFileInfoA", "str", FileName, "uint", 0, "str", sfi, "uint", sfi_size, "uint", 0x101)  ; 0x101 is SHGFI_ICON+SHGFI_SMALLICON.


If I use SHGFI_ICON instead of 0x101 (and change the type to "Str"), it wont work. My question is where can I find the "0x" values of these "Text" values.
Back to top
PhiLho



Joined: 27 Dec 2005
Posts: 6721
Location: France (near Paris)

PostPosted: Sun Jun 25, 2006 1:08 pm    Post subject: Reply with quote

I answered that (or something similar) in a topic you started...
Look at the links I give for ApiViewer or the API-Guide.
In short, these "strings" are actually kinds of variables, and are replaced by the C compiler by their values (provided by the above softwares).
So you can write, to keep these names (more meaningful than raw values):
SHGFI_ICON = 0x100
DllCall("Shell32\SHGetFileInfoA", "str", FileName, "uint", 0, "str", sfi, "uint", sfi_size, "uint", SHGFI_ICON)

_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group