Currently I am trying to implement a timer class in VBA. For that purpose I use the SetTimer and KillTimer functions of the Windows API...
This is the interface from Msdn:
UINT_PTR WINAPI SetTimer(
__in_opt HWND hWnd,
__in UINT_PTR nIDEvent,
__in UINT uElapse,
__in_opt TIMERPROC lpTimerFunc
);
And this is the way I declared the function wihtin my VBA-Module:
Private Declare Function SetTimer Lib "user32" (ByVal Handle As Long, _
ByVal TimerIDHandle As Any, _
ByVal ElapseTime As Long, _
ByVal AddressOfAndYourHandlerFunctionName As Long) As Long
'TimerIDHandle is of Type Any so I can pass Nothing to the function
I then Call the function this way:
Dim TimerID As Long
TimerID = SetTimer(Application.hWndAccessApp, ByVal 0&, Timer.Timeout, AddressOf TimeOutHandler)
As Vba does not accept a "Null" I have tried implementing "ByVal 0&". Is this the right way to do it?
Anyway...I call this function several times from the same Application and the function always returns 1 as an Identifier even though, according to Msdn, the function should return a unique ID for each timer that is created in the Window handle of the current Access Application.
Furthermore when I created only one timer the Callback function gets Called, but the Timer ID is given as 0, whereas the Settimer-Function returned a 1 at the time of initialization.
Here is my Callback Function Header:
Private Sub TimeOutHandler(ByVal WindowHandle As Long, _
ByVal TimerMessage As Long, _
ByVal TimerID As Long, _
ByVal ElapsedTime As Long)
Where am I wrong?
Any help is greatly appreciated of course ;-)
It worked. If it failed then it would have returned 0. You get a 0 for TimerID in the callback because you passed a 0 for the nIDEvent argument when you created the timer. You'll need to use the value that SetTimer returned to call KillTimer(). Think of it as a timer 'handle'.
You'll never get this code working in 64-bit mode so just declare the 2nd argument as Long.
Related
Currently, my console application can return Integer values from the console application via the kernel32 function ExitProcess.
Public Declare Sub ExitProcess Lib "kernel32" (ByVal uExitCode As Long)
How do I return string values from the console application to the batch file?
I want to return string values like Successfully transformed 100 batches... etc.
On most platforms (and also in Windows) process exit codes are integer values, but you could write string data to the standard output stream by using the GetStdHandle and WriteFile functions.
Update As requested, I´ll serve you an example.
First, you´ll need to import some more Windows functions and define the required constants. In addition to the before-mentioned GetStdHandle and WriteFile methods, the AttachConsole and FreeConsole methods are also required.
Private Const ATTACH_PARENT_PROCESS As Long = -1
Private Declare Function AttachConsole Lib "Kernel32" ( _
ByVal dwProcessId As Long) As Long
Private Declare Function FreeConsole Lib "Kernel32" () As Long
Private Const STD_OUTPUT_HANDLE As Long = -11&
Private Declare Function GetStdHandle Lib "Kernel32" ( _
ByVal nStdHandle As Long) As Long
Private Declare Function WriteFile Lib "Kernel32" ( _
ByVal hFile As Long, _
ByVal lpBuffer As String, _
ByVal nNumberOfBytesToWrite As Long, _
ByRef lpNumberOfBytesWritten As Long, _
lpOverlapped As Any) As Long
In my sample project, I just added a Module and defined a Sub Main method - this serves as the entry point for the app. Please notice, that you don´t get any output from the app when running it from the VB6 IDE debugger. You´ll need to compile it, and run it from a terminal window (for instance cmd.exe).
The first thing to do is to attach to the console of the parent process (which is the console of the terminal window). Otherwise, the GetStdHandle method will return zero.
Dim handle As Long
AttachConsole (ATTACH_PARENT_PROCESS)
handle = GetStdHandle(STD_OUTPUT_HANDLE)
Once the console handle is obtained, the WriteFile method can be used to print text to the console.
Dim s As String
Dim numberOfBytesWritten As Long
s = "Hello World."
WriteFile handle, s, Len(s), numberOfBytesWritten, ByVal 0&
Before finally calling ExitProcess, the FreeConsole method is used to detach the process from the parent console.
In the new 64-bit version of Excel 2016 on OSX I obtained through update today, the conditional compilation doesn't seem to be followed when checking for function definitions that don't have PtrSafe defined (as would be the case for 32-bit platforms). In this example, we have different definitions of the same function for different platforms, and when Excel loads the add-in it dies and complains about the third definition not having a PtrSafe in the function declaration (but of course it doesn't because it is for a 32-bit platform).
Is there any way of making Excel not die when it hits this code in VBA? Or is this just a bug in 64-bit Excel 2016 on OSX? Seems like an obvious bug to me. Where do I report bugs in Excel?
#If Mac Then
' Even though the functions are exported with a leading underscore, Excel 2011 for Mac doesn't want the leading underscore as part of name
Private Declare PtrSafe Function get_global_param_string_private Lib "libCoolProp.dylib" Alias "get_global_param_string" (ByVal param As String, ByVal Output As String, ByVal n As Integer) As Long
#ElseIf Win64 Then
Private Declare PtrSafe Function get_global_param_string_private Lib "CoolProp_xls_x64.dll" Alias "get_global_param_string" (ByVal param As String, ByVal Output As String, ByVal n As Integer) As Long
#Else
Private Declare Function get_global_param_string_private Lib "CoolProp_xls_std.dll" Alias "_get_global_param_string#12" (ByVal param As String, ByVal Output As String, ByVal n As Integer) As Long
#End If
Unless the API function itself is different for 64 and 32 bit windows it suffices to use the VBA7 switch (which starts at Office 2010) for Windows:
#If Mac Then
' Even though the functions are exported with a leading underscore, Excel 2011 for Mac doesn't want the leading underscore as part of name
Private Declare PtrSafe Function get_global_param_string_private Lib "libCoolProp.dylib" Alias "get_global_param_string" (ByVal param As String, ByVal Output As String, ByVal n As Integer) As Long
#ElseIf VBA7 Then
Private Declare PtrSafe Function get_global_param_string_private Lib "CoolProp_xls_x64.dll" Alias "get_global_param_string" (ByVal param As String, ByVal Output As String, ByVal n As Integer) As Long
#Else
Private Declare Function get_global_param_string_private Lib "CoolProp_xls_std.dll" Alias "_get_global_param_string#12" (ByVal param As String, ByVal Output As String, ByVal n As Integer) As Long
#End If
I have a quick question:
Somebody have a code snippet to hide a window completely.
Along the same lines as your other question, you can use the handle of the window you want to hide and call the ShowWindow API function using 0 for nCmdShow will hide the window.
Declaration
Private Declare Auto Function ShowWindow Lib "user32" (ByVal hwnd As Integer, nCmdShow As Integer) As Boolean
Usuage
ShowWindow(handle, 0)
use this Me.Visible = False or check this out http://msdn.microsoft.com/en-us/library/windows/desktop/ms633548(v=vs.85).aspx
I am using VB.NET and need to activate a certain window. Is this possible? If so, how?
You will need to use the Win32 API to do this.
First, find window you want to bring to front by calling FindWindow to obtain its handle, and then use SetForegroundWindow API to bring it to the foreground.
PInvoke contains declarations for these methods.
There are 2 solutions, one using Window API and another using pure VB.Net
you can use SetForegroundWindow(iHandle)
example with FindWindow to obtain Window handle
Public Declare Function SetForegroundWindow Lib "user32.dll" (ByVal hwnd As Integer) As Integer
Public Declare Auto Function FindWindow Lib "user32.dll" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
Dim hWnd As Integer
hWnd = FindWindow(strClassName, strWindowCaption)
If hWnd > 0 Then
SetForegroundWindow(hWnd)
End If
you can use AppActivate(iProcessId)
example with GetActiveAppProcess() to obtain input Window active process in an hook program
Dim hWnd As IntPtr
Dim inputProcess = GetActiveAppProcess()
hWnd = GetActiveAppProcess().MainWindowHandle
AppActivate(inputProcess.Id)
'you can also use SetForegroundWindow
'SetForegroundWindow(inputProcess..MainWindowHandle)
SendKeys.Send("^v")
I have a simple DLL written with VC6 with one function:
__declspec(dllexport) int myfunc(long a, unsigned char *b, unsigned char *c, unsigned char *d, unsigned char *e)
And im calling it from vb6 using:
Declare Function myfunc Lib "mylib.dll" (ByVal a As Long, ByVal b As String, ByVal c As String, ByVal d As String, ByVal e As String) As Long
....
dim a as long
dim b as string
dim c as string
dim d as string
dim e as string
dim r as long
r=myfunc(a,b,c,d,e)
Im getting "bad dll calling convention" error but I cant figure out why. Any ideas?
Generally speaking, 'bad DLL...' means what it says. VB6 requires the _stdcall convention (like the Win API) for any external functions it calls.
Try adding __stdcall to the C function prototype and see what happens.
Check out the Universal DLL function caller, by Paul Caton:
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=70195&lngWId=1
It will allow you to call pretty much any type of function from VB6.