Jump to content


Photo

MD5 Hash DllCall() / Hashes.dll


  • Please log in to reply
17 replies to this topic

#1 SKAN

SKAN
  • Administrators
  • 9062 posts

Posted 03 January 2006 - 07:28 AM

Somebody Please tell me how to do it!

I searched and found the following DLL
http://www.paehl.de/hashes_dll.zip
but not able to get proper result

Just one line of help is required. Somebody please translate and complete the following DllCall()

Result := DllCall("Hashes\testit",

Regards - Goyyah

#2 shimanov

shimanov
  • Members
  • 610 posts

Posted 03 January 2006 - 08:41 AM

An example demonstrating a call to his (Dirk's) library:

hash := DllCall( "hashes.dll\testit", "str", "hashes_dll.zip", "str", "SHA1", "uint", 0, "str" )

MsgBox, %hash%


#3 SKAN

SKAN
  • Administrators
  • 9062 posts

Posted 03 January 2006 - 11:36 AM

Thank you very much Shimanov,
It works!

The hash string is followed by copyright, so I modified it a bit

hash := DllCall( "hashes.dll\testit", "str", "hashes.dll", "str", "MD5", "uint", 0, "str" )
StringLeft,hash,hash,32
StringUpper,hash,hash
MsgBox, %hash%

I Thank you again for a very fast reply

arian.suresh@gmail.com

#4 Laszlo

Laszlo
  • Fellows
  • 4713 posts

Posted 03 January 2006 - 04:27 PM

If you use "StringTrimRight hash, hash, 68" instead of StringLeft..., it would work with any hash:
hash := DllCall("hashes.dll\testit", "str",A_ScriptFullPath, "str","SHA1", "uint",0, "str")

StringTrimRight hash, hash, 68   ; Remove copyright notice

MsgBox, %hash%


#5 shimanov

shimanov
  • Members
  • 610 posts

Posted 03 January 2006 - 06:01 PM

The hash string is followed by copyright


The author chose to append the copyright notice with the release for a reason. I left its removal up to you.

#6 SKAN

SKAN
  • Administrators
  • 9062 posts

Posted 03 January 2006 - 07:52 PM

Thanks for the tip Laszlo.

Now I have a situation. I need to periodically check (from a Timer ) whether a particular Folder Contents have changed, and if it has the Script will have to reload. This is required so because the script has dynamic submenus [in Tray Menu] which lists the contents of a folder

I tried the following code with success, but to my grief it takes 100's of seconds to complete when there are many files!

FileDelete,SysChk.txt
; I have to check C:\Download\*.* but using C:\Windows\System\*.* instead as example
Loop,C:\Windows\System\*.*,,1   
{
hash := DllCall( "hashes.dll\testit", "str", A_LOOPFILELONGPATH, "str", "MD5", "uint", 0, "str" )
StringTrimRight,hash,hash,68
Fileappend,%hash%,SysChk.txt
}
hash := DllCall( "hashes.dll\testit", "str", "SysChk.txt", "str", "MD5", "uint", 0, "str" )
StringTrimRight,hash,hash,68
StringUpper,hash,hash
IniRead,prev_hash,SysChk.INI,SYSTEMDIR,HashValue
Iniwrite,%hash%,SysChk.INI,SYSTEMDIR,HashValue
if prev_hash != ERROR
	if prev_hash!=%hash%
		Msgbox,System Directory Contents have Changed!
exitapp

Can somebody suggest whether there is a better and faster solution to
Ascertain whether the contents of a folder has changed

Please help..

#7 Laszlo

Laszlo
  • Fellows
  • 4713 posts

Posted 03 January 2006 - 08:13 PM

Is the problem that a file might have been downloaded a second time, and so the FileTime value is different although the file is still the same?

- If you don't worry about it, in a file loop you can crate a list of the file names, each in a new line with their modification time attached. Sort this string. When you look for changes compare a newly calculated list to the older one, they have to be exactly the same if there were no changes.

- If a second download bothers you, compute the CRC or the hash of the files at startup, and attach them to the lines in the file lists, as well as their size. New lists need not have hash values. Compare them to the old list, line-by-line, ignoring the hash values. If you find the same filename with different time, compare the sizes. If they are the same, only then you calculate the hash of the new file and compare it to the old hash.

CRC is a hundred times faster, but very rarely a collision could occur.

#8 Chris

Chris
  • Administrators
  • 10727 posts

Posted 03 January 2006 - 08:31 PM

To improve performance (though it might not help in this case), you could also try using LoadLibrary as described on the DllCall page.

#9 shimanov

shimanov
  • Members
  • 610 posts

Posted 03 January 2006 - 08:58 PM

The OS provides functionality to do what you have in mind. What version of Windows are you using?

#10 SKAN

SKAN
  • Administrators
  • 9062 posts

Posted 04 January 2006 - 10:23 AM

Dear Laszlo I tried something similar to your suggestion.

FileDelete,SysCheck.txt
Loop,%windir%\System\*.*,,1
{
FileGetSize,FileSize,%A_LoopFileLongPath%
FileSize=0000000000%FileSize%
StringRight,Filesize,FileSize,10
FileGetTime,FileTime,%A_LoopFileLongPath%
FileAppend,%FileTime% %FileSize% %A_LoopFileLongPath%`n,SysCheck.txt
}
hash := DllCall( "hashes.dll\testit", "str", "SysCheck.txt", "str", "MD5", "uint", 0, "str" )
StringTrimRight,hash,hash,68
StringUpper,hash,hash
IniRead,prev_hash,SysCheck.INI,SYSTEMDIR,HashValue
Iniwrite,%hash%,SysCheck.INI,SYSTEMDIR,HashValue
if prev_hash != ERROR
	if prev_hash!=%hash%
		Msgbox,System Directory Contents have Changed!
return

A few Lines from SysCheck.TXT
20051219190034 0000040960 C:\WINDOWS\SYSTEM\WSOCK32.DLL
20051219190034 0000002544 C:\WINDOWS\SYSTEM\CFGWIZ.DLL
19990423222200 0000065536 C:\WINDOWS\SYSTEM\CFGWIZ32.EXE
20051219190034 0000026848 C:\WINDOWS\SYSTEM\DINDI.DLL
This is faster and better, takes only a few seconds for "C:\Windows\System", but very suitable for folders with less files.

Chris:To improve performance (though it might not help in this case), you could also try using LoadLibrary as described on the DllCall page.


Thanks Chris, I forgot about using the LoadLibrary, though I am aware of it.

Shimanov/Laszlo/Chris: To have some idea on what kind of menu I am talking about, Please visit the link http://www.geocities...h/Artic001.html . The webpage has two Screen Captures (1024x768 Res) showing the menu

Shimanov, I work only in Windows 98 SE. I also have Windows XP but I don`t use Autohotkey in it. I only use XP to try programs that dont run in 98 SE

#11 shimanov

shimanov
  • Members
  • 610 posts

Posted 04 January 2006 - 05:33 PM

The following code demonstrates the OS facility to detect changes to files and directories (works with all versions of Windows):

goyyah: combine this detection code with your identification code

note: for further information check MSDN

#Persistent

path = testdir

OnExit, HandleExit

VarSetCapacity( array_h_notification, 16 )

h_notification[0] := FindFirstChangeNotification( path, true, 1 )				; FILE_NOTIFY_CHANGE_FILE_NAME
EncodeInteger( h_notification[0], 4, &array_h_notification, 0 )
if ( ErrorLevel or h_notification[0] = -1 )
{
	MsgBox, [FindFirstChangeNotification] failed: EL = %ErrorLevel%
	ExitApp
}

h_notification[1] := FindFirstChangeNotification( path, true, 2 )				; FILE_NOTIFY_CHANGE_DIR_NAME
EncodeInteger( h_notification[1], 4, &array_h_notification, 4 )
if ( ErrorLevel or h_notification[1] = -1 )
{
	MsgBox, [FindFirstChangeNotification] failed: EL = %ErrorLevel%
	ExitApp
}

h_notification[2] := FindFirstChangeNotification( path, true, 8 )				; FILE_NOTIFY_CHANGE_SIZE
EncodeInteger( h_notification[2], 4, &array_h_notification, 8 )
if ( ErrorLevel or h_notification[2] = -1 )
{
	MsgBox, [FindFirstChangeNotification] failed: EL = %ErrorLevel%
	ExitApp
}

h_notification[3] := FindFirstChangeNotification( path, true, 16 )				; FILE_NOTIFY_CHANGE_LAST_WRITE
EncodeInteger( h_notification[3], 4, &array_h_notification, 12 )
if ( ErrorLevel or h_notification[3] = -1 )
{
	MsgBox, [FindFirstChangeNotification] failed: EL = %ErrorLevel%
	ExitApp
}

SetTimer, timer_DetectChange, 1000
return

HandleExit:
	loop, 4
	{
		temp := "h_notification[" ( A_Index-1 ) "]"
		MsgBox, % DllCall( "FindCloseChangeNotification", "uint", %temp% )
	}
ExitApp

timer_DetectChange:
	result := DllCall( "WaitForMultipleObjects", "uint", 4, "uint", &array_h_notification, "int", false, "uint", 0 )
	if ( result >= 0 and result <= 3 )
	{
		if ( result = 0 )
			MsgBox, change has been detected: FILE_NOTIFY_CHANGE_FILE_NAME
		else if ( result = 1 )
			MsgBox, change has been detected: FILE_NOTIFY_CHANGE_DIR_NAME
		else if ( result = 2 )
			MsgBox, change has been detected: FILE_NOTIFY_CHANGE_SIZE
		else if ( result = 3 )
			MsgBox, change has been detected: FILE_NOTIFY_CHANGE_LAST_WRITE
			
		DllCall( "FindNextChangeNotification", "uint", h_notification[%result%] )
	}
return

EncodeInteger( p_value, p_size, p_address, p_offset )
{
	loop, %p_size%
		DllCall( "RtlFillMemory"
			, "uint", p_address+p_offset+A_Index-1
			, "uint", 1
			, "uchar", ( p_value >> ( 8*( A_Index-1 ) ) ) & 0xFF )
}

FindFirstChangeNotification( p_path, p_recurse, p_filter )
{
	return, DllCall( "FindFirstChangeNotification"
						, "str", p_path
						, "int", p_recurse
						, "uint", p_filter )
}


#12 Laszlo

Laszlo
  • Fellows
  • 4713 posts

Posted 04 January 2006 - 06:36 PM

Thanks, Shimanov, for demonstrating the OS facility to detect changes to files and directories. It should be posted in the Scripts section, so we can find it if we need to.

In this particular case, though, the time consuming part is to check, if a file with a new date/time stamp is really different from its previous version (downloaded again). Although the Windows DLL calls present a fast way to detect changes, the saving is not much: a loop collecting file names and dates is pretty fast (accessing only the directory buffer in memory for reasonable size directories). Hashing is the slow part, especially with large files.

#13 shimanov

shimanov
  • Members
  • 610 posts

Posted 04 January 2006 - 10:09 PM

In this particular case, though, the time consuming part is to check, if a file with a new date/time stamp is really different from its previous version (downloaded again). Although the Windows DLL calls present a fast way to detect changes, the saving is not much: a loop collecting file names and dates is pretty fast (accessing only the directory buffer in memory for reasonable size directories). Hashing is the slow part, especially with large files.


Actually, detection will likely occur more often than identification. Then for a larger number of files distributed over a larger number of directories, the OS method will save time when used over an extended period. Not only that, but you can also narrow the parameters for identification by considering the context of detection (i.e., FILE_NOTIFY_CHANGE...).

#14 Laszlo

Laszlo
  • Fellows
  • 4713 posts

Posted 04 January 2006 - 11:23 PM

I have a program constantly backing up my changed files of certain types in specified directories to a small second drive: AutoSave. It works great, but we could get similar functionality for free with an AHK script, using FILE_NOTIFY_CHANGE... Could you, my dear Shimanov, post the basic function in the Scripts section? It would be really useful!

#15 shimanov

shimanov
  • Members
  • 610 posts

Posted 05 January 2006 - 04:50 AM

similar functionality for free with an AHK script


Both good.

post the basic function in the Scripts section


I decided to post a more than basic version to facilitate use by most users. Hopefully, it will be straightforward enough for general use. In any case, you are certainly capable of modifying one of the posted examples to suit your needs.