DllCall with a msdn macro - not working Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
GRUWEZ
Posts: 14
Joined: 16 Nov 2021, 10:20

DllCall with a msdn macro - not working

Post by GRUWEZ » 07 Dec 2021, 06:05

Hello Everyone,

So briefly - the big question is - where can i found the MonthCal_GetToday Macro to make it workes in my dllcall function

And in details, this is what i already tried.

I'm just trying to run this peace of code for the MonthCal_GetToday Macro , but the error level for my dllcall function return me -4 which means that The specified function could not be found inside the DLL.

So i tried the usual dll of windows : User32.dll, Kernel32.dll, ComCtl32.dll, or Gdi32.dll. - always returning me errorlever -4.

After this, i read a bit of msnd doc - and they said that the header is commctrl.h.
https://docs.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-monthcal_gettoday

I don't understand if i can use it as a dll in dllcall function ?
When i try to use it - dllcall returns me a function of -3. which means :
-3: The specified DllFile could not be accessed or loaded. If no explicit path was specified for DllFile, the file must exist in the system's PATH or A_WorkingDir. This error might also occur if the user lacks permission to access the file, or if AutoHotkey is 32-bit and the DLL is 64-bit or vice versa.
I tried to update a 64bit ahk version - i also tried to run as admin my actual script. I tried to copy my commctrl.h file into my actual directory (where my script is)

Nothing works.
Someone know what should i do ?
Here's my code below with all my fails :

Code: Select all

VarSetCapacity(DateDuJour, 16, 0)
DllCall("D:\Informatique\Logiciels\VisualStudioCSharp\Include\10.0.18362.0\um\CommCtrl.h\MonthCal_GetToday", "Ptr", &hwndOutPutVar, "Ptr", DateDuJour )
DllCall("CommCtrl.h\MonthCal_GetToday", "Ptr", &hwndOutPutVar, "Ptr", DateDuJour ) ; return -3
DllCall("User32\MonthCal_GetToday", "Ptr", &hwndOutPutVar, "Ptr", DateDuJour ) ; return -4
DllCall("ComCtl32\MonthCal_GetToday", "Ptr", &hwndOutPutVar, "Ptr", DateDuJour ) ; return -4
MsgBox  %ErrorLevel%


Thanks for any help

teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: DllCall with a msdn macro - not working

Post by teadrinker » 07 Dec 2021, 07:50

GRUWEZ wrote: So briefly - the big question is - where can i found the MonthCal_GetToday Macro to make it workes in my dllcall function
You can't, those macros don't work with DllCall. You have to find a corresponding function or a message. In this case you can use MCM_GETTODAY instead:
MSDN wrote:You can use this macro or send the MCM_GETTODAY message explicitly.

swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: DllCall with a msdn macro - not working

Post by swagfag » 07 Dec 2021, 13:19

u download a Windows sdk version matching ur windows version and look for the macro inside the .headers in it that the docs specify. then u see how the macro is implemented. its not always in terms of a particular function

GRUWEZ
Posts: 14
Joined: 16 Nov 2021, 10:20

Re: DllCall with a msdn macro - not working

Post by GRUWEZ » 07 Dec 2021, 16:34

teadrinker wrote:
07 Dec 2021, 07:50
GRUWEZ wrote: So briefly - the big question is - where can i found the MonthCal_GetToday Macro to make it workes in my dllcall function
You can't, those macros don't work with DllCall. You have to find a corresponding function or a message. In this case you can use MCM_GETTODAY instead:
MSDN wrote:You can use this macro or send the MCM_GETTODAY message explicitly.
Hey, thanks for your message ,
when i try to send the message - it's not selecting the date. do you have a special idea why ? - my code below

Code: Select all

ConvertNormalDateToSystemTime(YYYYMMDD, ByRef SystemTime)
; this return a  SystemTime format date from a normal date
{
	YYYYMMDD.=000000
	YYYYMMDDHHMISS:=YYYYMMDD
	
	
	VarSetCapacity(SystemTime, 16, 0)  ; This struct consists of 8 UShorts (i.e. 8*2=16).
	Int := SubStr(YYYYMMDDHHMISS, 1, 4)  ; YYYY (year)
	NumPut(Int, SystemTime, 0, "UShort")
	Int := SubStr(YYYYMMDDHHMISS, 5, 2)  ; MM (month of year, 1-12)
	NumPut(Int, SystemTime, 2, "UShort")
	Int := SubStr(YYYYMMDDHHMISS, 7, 2)  ; DD (day of month)
	NumPut(Int, SystemTime, 6, "UShort")
	Int := SubStr(YYYYMMDDHHMISS, 9, 2)  ; HH (hour in 24-hour time)
	NumPut(Int, SystemTime, 8, "UShort")
	Int := SubStr(YYYYMMDDHHMISS, 11, 2) ; MI (minute)
	NumPut(Int, SystemTime, 10, "UShort")
	Int := SubStr(YYYYMMDDHHMISS, 13, 2) ; SS (second)
	NumPut(Int, SystemTime, 12, "UShort")
	
	return SystemTime
	
	
}

WinActivate ahk_class AutoHotkeyGUI, ShowDate

MCM_FIRST:= 0x1000 
MCM_SETCURSEL:= MCM_FIRST + 2
MyDate:= 20211115
VarSetCapacity(dateASelectionnerDansCalendrier, 16, 0)
ConvertNormalDateToSystemTime(MyDate, dateASelectionnerDansCalendrier)

ControlGet, hwndOutPutVar, Hwnd ,, SysMonthCal321, ahk_class AutoHotkeyGUI, ShowDate

SendMessage, %MCM_SETCURSEL% , 0 , %dateASelectionnerDansCalendrier% ,  , ahk_id %hwndOutPutVar%
MsgBox Le message est %MCM_SETCURSEL% et le niveau erreur est : %ErrorLevel%

teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: DllCall with a msdn macro - not working

Post by teadrinker » 07 Dec 2021, 19:23

Why wouldn't you use GuiControl instead of a message?
You are trying to pass %dateASelectionnerDansCalendrier%, but the pointer must be passed (&dateASelectionnerDansCalendrier).
MSDN wrote:lParam
Pointer to a SYSTEMTIME structure that contains the date to be set as the current selection.
Also you must keep in mind, that a pointer is valid only in the context of its own process, if you try passing it to another script, you'll fail.

GRUWEZ
Posts: 14
Joined: 16 Nov 2021, 10:20

Re: DllCall with a msdn macro - not working

Post by GRUWEZ » 08 Dec 2021, 03:09

teadrinker wrote:
07 Dec 2021, 19:23
Why wouldn't you use GuiControl instead of a message?
You are trying to pass %dateASelectionnerDansCalendrier%, but the pointer must be passed (&dateASelectionnerDansCalendrier).
MSDN wrote:lParam
Pointer to a SYSTEMTIME structure that contains the date to be set as the current selection.
Also you must keep in mind, that a pointer is valid only in the context of its own process, if you try passing it to another script, you'll fail.

Hello,
Gui control will not work in this case bc i don't have the source code of this one. What should i do to send the message to my window if the pointer can only work in my script ? Don't understand why we creates messages that can't be send. Should i use an other method to send the pointer outside ?

Thanks for your relevent remarks :)

Gilles

teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: DllCall with a msdn macro - not working

Post by teadrinker » 08 Dec 2021, 04:20

If the SysMonthCal32 control belongs to another process, you have to create a buffer in that process, write the date there, and pass the pointer of the buffer. The class RemoteBuffer can be used for this purpose. An example:

Code: Select all

ControlGet, hMonthCal, Hwnd,, SysMonthCal321, ahk_class AutoHotkeyGUI, ShowDate
if !hMonthCal
   throw "Failed to get hwnd of SysMonthCal321"
WinGet, PID, PID, ahk_id %hMonthCal%

MyDate := "20211115"
ConvertDateToSystemTime(MyDate, SystemTime)
RB := new RemoteBuffer(PID, 16)
RB.Write(&SystemTime, 16)
SendMessage, MCM_SETCURSEL := 0x1002,, RB.ptr,, ahk_id %hMonthCal%
if (ErrorLevel != 1)
   throw "Failed to set new date"
RB := ""

ConvertDateToSystemTime(YYYYMMDD, ByRef SystemTime) {
   VarSetCapacity(SystemTime, 16, 0)
   NumPut( SubStr(YYYYMMDD, 1, 4), SystemTime )
   NumPut( SubStr(YYYYMMDD, 5, 2), SystemTime, 2 )
   NumPut( SubStr(YYYYMMDD, 7, 2), SystemTime, 6 )
   Return &SystemTime
}

class RemoteBuffer
{
   __New(PID, size) {
      static flags := (PROCESS_VM_OPERATION := 0x8) | (PROCESS_VM_WRITE := 0x20) | (PROCESS_VM_READ := 0x10)
           , Params := ["UInt", MEM_COMMIT := 0x1000, "UInt", PAGE_READWRITE := 0x4, "Ptr"]
         
      if !this.hProc := DllCall("OpenProcess", "UInt", flags, "Int", 0, "UInt", PID, "Ptr")
         throw Exception("Can't open remote process PID = " . PID . "`nA_LastError: " . A_LastError, "RemoteBuffer.__New")
      
      if !this.ptr := DllCall("VirtualAllocEx", "Ptr", this.hProc, "Ptr", 0, "Ptr", size, Params*) {
         DllCall("CloseHandle", "Ptr", this.hProc)
         throw Exception("Can't allocate memory in remote process PID = " . PID . "`nA_LastError: " . A_LastError, "RemoteBuffer.__New")
      }
   }
   __Delete() {
      DllCall("VirtualFreeEx", "Ptr", this.hProc, "Ptr", this.ptr, "UInt", 0, "UInt", MEM_RELEASE := 0x8000)
      DllCall("CloseHandle", "Ptr", this.hProc)
   }  
   Read(ByRef localBuff, size, offset = 0) {
      VarSetCapacity(localBuff, size, 0)
      if !DllCall("ReadProcessMemory", "Ptr", this.hProc, "Ptr", this.ptr + offset, "Ptr", &localBuff, "Ptr", size, "PtrP", bytesRead)
         throw Exception("Can't read data from remote buffer`nA_LastError: " . A_LastError, "RemoteBuffer.Read")
      Return bytesRead
   }
   Write(pData, size, offset = 0) {
      if !res := DllCall("WriteProcessMemory", "Ptr", this.hProc, "Ptr", this.ptr + offset, "Ptr", pData, "Ptr", size, "PtrP", bytesWritten)
         throw Exception("Can't write data to remote buffer`nA_LastError: " . A_LastError, "RemoteBuffer.Write")
      Return bytesWritten
   }
}

GRUWEZ
Posts: 14
Joined: 16 Nov 2021, 10:20

Re: DllCall with a msdn macro - not working

Post by GRUWEZ » 08 Dec 2021, 05:58

NOW IT'S WORKING !!!! THANKS !

GRUWEZ
Posts: 14
Joined: 16 Nov 2021, 10:20

Re: DllCall with a msdn macro - not working

Post by GRUWEZ » 09 Dec 2021, 04:32

teadrinker wrote:
08 Dec 2021, 04:20
If the SysMonthCal32 control belongs to another process, you have to create a buffer in that process, write the date there, and pass the pointer of the buffer. The class RemoteBuffer can be used for this purpose. An example:

Code: Select all

ControlGet, hMonthCal, Hwnd,, SysMonthCal321, ahk_class AutoHotkeyGUI, ShowDate
if !hMonthCal
   throw "Failed to get hwnd of SysMonthCal321"
WinGet, PID, PID, ahk_id %hMonthCal%

MyDate := "20211115"
ConvertDateToSystemTime(MyDate, SystemTime)
RB := new RemoteBuffer(PID, 16)
RB.Write(&SystemTime, 16)
SendMessage, MCM_SETCURSEL := 0x1002,, RB.ptr,, ahk_id %hMonthCal%
if (ErrorLevel != 1)
   throw "Failed to set new date"
RB := ""

ConvertDateToSystemTime(YYYYMMDD, ByRef SystemTime) {
   VarSetCapacity(SystemTime, 16, 0)
   NumPut( SubStr(YYYYMMDD, 1, 4), SystemTime )
   NumPut( SubStr(YYYYMMDD, 5, 2), SystemTime, 2 )
   NumPut( SubStr(YYYYMMDD, 7, 2), SystemTime, 6 )
   Return &SystemTime
}

class RemoteBuffer
{
   __New(PID, size) {
      static flags := (PROCESS_VM_OPERATION := 0x8) | (PROCESS_VM_WRITE := 0x20) | (PROCESS_VM_READ := 0x10)
           , Params := ["UInt", MEM_COMMIT := 0x1000, "UInt", PAGE_READWRITE := 0x4, "Ptr"]
         
      if !this.hProc := DllCall("OpenProcess", "UInt", flags, "Int", 0, "UInt", PID, "Ptr")
         throw Exception("Can't open remote process PID = " . PID . "`nA_LastError: " . A_LastError, "RemoteBuffer.__New")
      
      if !this.ptr := DllCall("VirtualAllocEx", "Ptr", this.hProc, "Ptr", 0, "Ptr", size, Params*) {
         DllCall("CloseHandle", "Ptr", this.hProc)
         throw Exception("Can't allocate memory in remote process PID = " . PID . "`nA_LastError: " . A_LastError, "RemoteBuffer.__New")
      }
   }
   __Delete() {
      DllCall("VirtualFreeEx", "Ptr", this.hProc, "Ptr", this.ptr, "UInt", 0, "UInt", MEM_RELEASE := 0x8000)
      DllCall("CloseHandle", "Ptr", this.hProc)
   }  
   Read(ByRef localBuff, size, offset = 0) {
      VarSetCapacity(localBuff, size, 0)
      if !DllCall("ReadProcessMemory", "Ptr", this.hProc, "Ptr", this.ptr + offset, "Ptr", &localBuff, "Ptr", size, "PtrP", bytesRead)
         throw Exception("Can't read data from remote buffer`nA_LastError: " . A_LastError, "RemoteBuffer.Read")
      Return bytesRead
   }
   Write(pData, size, offset = 0) {
      if !res := DllCall("WriteProcessMemory", "Ptr", this.hProc, "Ptr", this.ptr + offset, "Ptr", pData, "Ptr", size, "PtrP", bytesWritten)
         throw Exception("Can't write data to remote buffer`nA_LastError: " . A_LastError, "RemoteBuffer.Write")
      Return bytesWritten
   }
}

Is it possible to send the message also with an array ? and use the same method ?
I mean with 2 systemTimestructure variable that i put in an array object. After i send those into my monthcall ?

teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: DllCall with a msdn macro - not working

Post by teadrinker » 09 Dec 2021, 05:00

But what do you want to achieve by this?

GRUWEZ
Posts: 14
Joined: 16 Nov 2021, 10:20

Re: DllCall with a msdn macro - not working

Post by GRUWEZ » 09 Dec 2021, 05:03

teadrinker wrote:
09 Dec 2021, 05:00
But what do you want to achieve by this?
I have an other monthcal but with multiselected option on my work facturation program , and i need to send this message
https://docs.microsoft.com/en-us/windows/win32/controls/mcm-setselrange - which work only with array...

teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

Re: DllCall with a msdn macro - not working  Topic is solved

Post by teadrinker » 09 Dec 2021, 05:55

Try this:

Code: Select all

ControlGet, hMonthCal, Hwnd,, SysMonthCal321, ahk_class AutoHotkeyGUI, ShowDate
if !hMonthCal
   throw "Failed to get hwnd of SysMonthCal321"
WinGet, PID, PID, ahk_id %hMonthCal%

MyDate1 := "20211115"
MyDate2 := "20211125"

ConvertDateToSystemTime(MyDate1, SystemTime1)
ConvertDateToSystemTime(MyDate2, SystemTime2)

RB := new RemoteBuffer(PID, 32)
RB.Write(&SystemTime1, 16)
RB.Write(&SystemTime2, 16, 16)

SendMessage, MCM_SETSELRANGE := 0x1006,, RB.ptr,, ahk_id %hMonthCal%
if (ErrorLevel != 1)
   throw "Failed to set date range"
RB := ""

ConvertDateToSystemTime(YYYYMMDD, ByRef SystemTime) {
   VarSetCapacity(SystemTime, 16, 0)
   NumPut( SubStr(YYYYMMDD, 1, 4), SystemTime )
   NumPut( SubStr(YYYYMMDD, 5, 2), SystemTime, 2 )
   NumPut( SubStr(YYYYMMDD, 7, 2), SystemTime, 6 )
   Return &SystemTime
}

class RemoteBuffer
{
   __New(PID, size) {
      static flags := (PROCESS_VM_OPERATION := 0x8) | (PROCESS_VM_WRITE := 0x20) | (PROCESS_VM_READ := 0x10)
           , Params := ["UInt", MEM_COMMIT := 0x1000, "UInt", PAGE_READWRITE := 0x4, "Ptr"]
         
      if !this.hProc := DllCall("OpenProcess", "UInt", flags, "Int", 0, "UInt", PID, "Ptr")
         throw Exception("Can't open remote process PID = " . PID . "`nA_LastError: " . A_LastError, "RemoteBuffer.__New")
      
      if !this.ptr := DllCall("VirtualAllocEx", "Ptr", this.hProc, "Ptr", 0, "Ptr", size, Params*) {
         DllCall("CloseHandle", "Ptr", this.hProc)
         throw Exception("Can't allocate memory in remote process PID = " . PID . "`nA_LastError: " . A_LastError, "RemoteBuffer.__New")
      }
   }
   __Delete() {
      DllCall("VirtualFreeEx", "Ptr", this.hProc, "Ptr", this.ptr, "UInt", 0, "UInt", MEM_RELEASE := 0x8000)
      DllCall("CloseHandle", "Ptr", this.hProc)
   }  
   Read(ByRef localBuff, size, offset = 0) {
      VarSetCapacity(localBuff, size, 0)
      if !DllCall("ReadProcessMemory", "Ptr", this.hProc, "Ptr", this.ptr + offset, "Ptr", &localBuff, "Ptr", size, "PtrP", bytesRead)
         throw Exception("Can't read data from remote buffer`nA_LastError: " . A_LastError, "RemoteBuffer.Read")
      Return bytesRead
   }
   Write(pData, size, offset = 0) {
      if !res := DllCall("WriteProcessMemory", "Ptr", this.hProc, "Ptr", this.ptr + offset, "Ptr", pData, "Ptr", size, "PtrP", bytesWritten)
         throw Exception("Can't write data to remote buffer`nA_LastError: " . A_LastError, "RemoteBuffer.Write")
      Return bytesWritten
   }
}

GRUWEZ
Posts: 14
Joined: 16 Nov 2021, 10:20

Re: DllCall with a msdn macro - not working

Post by GRUWEZ » 09 Dec 2021, 05:58

Yeah that works - thanks ;)

Post Reply

Return to “Ask for Help (v1)”