How to Inspect Call Stack - ms-access

Would it be possible to see the CallStack in VBA for MS Access 2003? That is to say, would it be possible to see from what procedure or function another function was called?

At runtime, View menu -> Call Stack (or press CTRL + L).

There is no programmatic way in VBA to view the call stack that I know of. The usual solution to this problem is to use some structure to track calling of functions, but it always seems like a kludge to me, and really of use only when programming (not at runtime), in which case it seems to me that the VBE's built-in capability for seeing the call stack is sufficient.
And, BTW, I always put the call stack button on my VBE toolbar, since it's one of the most frequently used functions for me. I also add the compile button -- I think it's crazy that it's not on the toolbar by default because it encourages people to code without ever forcing a compile. Then again, Access 2000 didn't even use Option Explicit by default (supposedly for consistency with the other apps using the VBE -- in other words, dumb down Access in order to make it consistent with apps that aren't nearly as code-heavy).
But I digress...

Eventually, add an optional parameter to your function, and pass the caller name that way. For forms, you can use Me.Name as the parameter.

Yes it's possible, BUT it's not quite usefull!
Private Declare Sub SetMode Lib "vba332.dll" Alias "EbSetMode" (ByVal lngMode As Long)
Private Declare Function GetCallStackCount Lib "vba332.dll" Alias "EbGetCallstackCount" (lngCount As Long) As Long
Private Declare Function GetCallStackFunction Lib "vba332.dll" Alias "EbGetCallstackFunction" (ByVal Lvl As Long, ByRef strBase As String, ByRef strModule As String, ByRef strFunction As String, ByRef Done As Long) As Long
Before use GetCallStackCount and GetCallStackFunction call SetMode(2), and after SetMode(1).

Related

Late Binding Global Variables?

I'm using VBA for Excel. From my understanding, global variables need to be declared outside of any subs. That's the only way they can be accessed by all subs.
At the meantime, I want to do late binding to reference the "Microsoft Scripting Runtime" library(in order to use the dictionary object type) so that an end user doesn't have to do it himself.
My code is as below:
On Error Resume Next
strGUID = "{420B2830-E718-11CF-893D-00A0C9054228}"
ThisWorkbook.VBProject.References.AddFromGuid GUID:=strGUID, Major:=1, Minor:=0
Dim Dic1 As Object
Set Dic1 = CreateObject("Scripting.Dictionary")
Dim Dic2 As Object
Set Dic2 = CreateObject("Scripting.Dictionary")
What if I want to declare global dictionary object with late binding? It looks like VBA won't allow me to put any code outside of the subs (other than the declarations).
How may I declare a global dictionary object without needing the end user configure library reference himself? Shall I don the following?
Dim Dic1 As Object
Dim Dic2 As Object
Sub Prog1()
On Error Resume Next
strGUID = "{420B2830-E718-11CF-893D-00A0C9054228}"
ThisWorkbook.VBProject.References.AddFromGuid GUID:=strGUID, Major:=1, Minor:=0
Set Dic1 = CreateObject("Scripting.Dictionary")
Set Dic2 = CreateObject("Scripting.Dictionary")
End Sub
Like the VBA code itself, project references don't magically disappear when your user opens your host workbook. They're saved along with the code in the host document.
So, the premise of your question is wrong: users never need to tweak project references.
Also the Scripting Runtime type library is standard issue and has been shipped the exact same version on every single Windows machine built this century (even before that), which means unless your code needs to run on a Mac, there's no need to ever late-bind the Scripting Runtime library.
And if your code needs to run on a Mac, the library won't late-bind anyway because it won't be found on the host machine, so late-binding the Scripting Runtime only serves to make silly typos and introduce other easily avoidable bugs that IntelliSense helps preventing.
ThisWorkbook.VBProject.References.AddFromGuid GUID:=strGUID, Major:=1, Minor:=0
This defeats the entire purpose of late-binding: it's using the VBIDE extensibility library (which requires lowered macro security settings) to programmatically add a reference that you can easily add at design-time through the VBE's Tools menu.
Late-bound code doesn't need the reference at all. Not at compile-time, not at run-time.
Add the reference, save, then declare your objects As Scripting.Dictionary and enjoy the benefits of early-bound code.
Set Dic1 = New Scripting.Dictionary
That's all you need.
What if I want to declare global dictionary object with late binding? It looks like VBA won't allow me to put any code outside of the subs (other than the declarations).
Late binding isn't any different than early binding in that aspect. The only difference between late and early bound code is the As clause of the declaration:
Private foo As Object ' no compile-time type knowledge: late-bound
Private bar As Dictionary ' compile-time type knowledge: early-bound
How you're initializing that object reference makes no difference to the late/early binding nature of the declaration.
This looks up a ProgID in the registry to find the library and the type:
Set foo = CreateObject("Scripting.Dictionary")
This uses the project references:
Set foo = New Scripting.Dictionary
Both are correct, and both will work against either early or late-bound declarations. Except, if you already have a reference to the type library, there's not really a need to go hit the registry to locate that library - just New it up!
Global variables are really not needed and should be avoided. However, if you have decided to use them for a your own reasons, you can put them in the Workbook_Open event:
Option Explicit
Dim Dic1 As Object
Dim Dic2 As Object
Private Sub Workbook_Open()
Set Dic1 = CreateObject("Scripting.Dictionary")
Set Dic2 = CreateObject("Scripting.Dictionary")
End Sub
Thus, it would create the object every time the workbook is opened.

Auto keyboard by using SendMessage

int VK_F_DOWN = GetVirtualKey('F', 0);
int VK_F_UP = GetVirtualKey('F', 1);
HWND hWnd = FindWindow(NULL,L"Calculator.exe");
SendMessage(hWnd, WM_KEYDOWN, toascii('F'), VK_F_DOWN);
SendMessage(hWnd, WM_KEYUP, toascii('F'), VK_F_UP);
It doesn't work on the Calculator.exe,however it can work on my visual studio when I change hWnd to HWND(0xFFFF).
And I also already got a non-zero hWnd. What am I missing here? Like authority or something?
Sounds like User Interface Privilege Isolation. As the Wikipedia article explains, you can request the access you want in your application manifest.
That said, you should be using SendInput rather than SendMessage. See one of Raymond Chen's blog entries on that point.

Numlock and CAPSLOCK turned always ON in VBA Access

Hello i have a form written in VBA Access , when i type or select some values from comboboz or text some values, my NUMLOCK And CAPSLOCK key are turning OFF, how to make that they ALWAYS will be ON , i can't figure how?
this has code that will check and set capslock, numlock and scrolllock.
It uses the windows APIs
Private Declare Function GetKeyboardState Lib "user32" _
(pbKeyState As Byte) As Long
Private Declare Function SetKeyboardState Lib "user32" _
(lppbKeyState As Byte) As Long
to check and set the keyboard state - with this API, other fun things are available, such as playing with the windows key.

Fortran: Calling a function in a module from a procedure in another module

I admit the title might be a bit obscure, so let me give an example of what I want to do and what doesn't work. I have a main program which calls a subroutine which is in a module:
Program Test_program
Use module_A
Implicit none
Integer :: i
i = 1
call subroutine_A(i)
End program Test_program
this subroutine_A is in module A, and in turns calls a function_B which is in module_B:
module module_A
use module_B
implicit none
contains
subroutine subroutine_A(i)
implicit none
integer, intent(in) :: i
double precision :: j
j = function_B(i)
end subroutine subroutine_A
end module module_A
and finally, module_B looks like this:
module module_B
Implicit none
Contains
double precision function function_B(i)
implicit none
integer,intent(in) :: i
function_B = 5.d0*i
end function function_B
end module module_B
the program and modules are in different files. Unfortunately, this does not compile, as I get an error message:
ERROR Subroutine_A: This reference to subroutine function_B is not in a CALL statement.
It seems the program believes that function_B is a subroutine, so I am not sure what to do.
By the way, I am trying to use proper encapsulation of my subroutines and functions using modules as I was told to, but if this is not the proper way I am open to suggestions (I was told not to use interfaces but modules instead hence this test).
Thanks
My apologies, I actually "solved" the mystery: instead of using the name function_B, I was using the name Compute_Error. When I changed that function name to something else, the method above worked. It seems some library I link to somewhere has a subroutine compute_error, though the the error message did not tell me which one, or if that was the issue for sure. Anyway, sorry again but I guess I can let the post since it helps to see how to link modules and procedures (I did not find many examples of that particular example on the internet).
Of course of this way of using modules and procedures is not the proper way, feel free to add some useful knowledge.

intellisense functionality in a custom VBA function?

In the standard IDE for VBA, intellisense is built-in to many standard VBA functions. i.e. the buttons variable for msgbox() gives you a list of options for how you want the messagebox to be displayed. This way, the developer doesn't have to memorize or look up the options every time function is used.
Can I achieve the same for my custom VBA functions? This is a rough example, but can i write something like:
Public Function DoSomething(X as string)(Options X="Opt1","Opt2") as variant
...
When I call this function, I would get a pop-up giving my options for X as Opt1 and Opt2
You'll need to declare your own enumerations, and then define the parameter to your functions as that enumerated type.
Public Enum eOptions
Option1
Option2
End Enum
public Function DoSomething(ByVal x as string, Byval MyOption as eOptions)
When you call the function ala this:
Call DoSomething("myValue", Option2)
You'll see the values available for the second parameter to the function as either "Option1" or "Option2".