Why would some DLL functions fail on 64-bit Windows? - dll

I'm trying to run some LotusScript code (very similar to Visual Basic) in Lotus Domino on Windows servers.
The code calls some Windows API functions, and works fine on 32-bit Windows 2003 servers, but doesn't work on the one 64-bit server we've tried it on.
Here's one of our external function declarations:
Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" _
(Byval lpFile As String, Byval lpDirectory As String, Byval lpResult As String) As Long
When trying to call that function, LotusScript produces the error message "External function not found".
I have tried both removing the Alias from the declaration, and changing the alias to "FindExecutable" with the same result.
I have also:
- For comparison, tried calling the GetForegroundWindow function in user32.dll - this works.
- Used the Dir function to confirm that shell32 exists with the path "c:\windows\syswow64\shell32.dll", then...
- Changed the Lib in the declaration to the dll's full path - this produces "Error in loading DLL" when calling the function.
Is there anything that must be done differently when calling shell32 functions on a 64-bit server?
Any other reason why the function call would fail on one particular server?

Just ran into this myself with a custom 64-bit DLL on 64-bit Domino. It appears it may be a known issue on 64-bit versions of Domino that IBM has decided to term as a "permanent restriction":
LO47066: "EXTERNAL FUNCTION NOT FOUND." ERROR FROM LOTUSSCRIPT AGENT USING SOME DLL FUNCTIONS IN DOMINO 64-BIT

My guess is that the As Long might be the culprit here - it probably is a bit integer on 32 bit and 64 bit on 64 bit...

Did you try using "Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableW" "

The program executing that script, is that a 64-bit application? If that's the case it is possible that this application cannot load 32-bit DLLs. (That would be the second problem)
To track down the first problem, load shell32.dll explicitly using LoadLibrary (don't use the full path!) and then use GetModuleFileName to get the full file name loaded. There can be all kinds of things responsible for messing with DLL paths. (WOW layer, UAC, path variable, ...)
If that actually works, you can try using Dependency Walker to see if FindExecutable is exported, but I think you'll run into problems before that.

Related

Are there native functions in VBA that handle serial communication similar to how the WSC32.DLL library does?

I am trying to fix some ~20 year old VBA code in Access that uses Windows Standard Serial Communications created by MarshallSoft Computing. The 32 bit version stopped working. For implementation reasons, it would be a lot easier to use something native in VBA that doesn't require installing a new library. The code just uses a handful of the WSC32 functions and it would be great if there was a native library in VBA that paralleled those functions. Any help is appreciated!
Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" _
(ByVal lpFileName As String, ByVal dwDesiredAccess As Long, _
ByVal dwShareMode As Long, lpSecurityAttributes As Any, _
ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As Long
https://gist.github.com/heiswayi/f47dfd8dc38955322bef is the David M. Hitchner example.
A search for "Darren Richards Win32 comms API wrapper for VBA" gave me some links (on Google, not on Bing) to postings of the (shorter) Darren Richards example, but not an original source.
From http://www.hardandsoftware.net/NETCommOCX.htm, NETCOMM.OCX is a way of using the original MSCOMM32.OCX in VBA. I agree that using the native windows API is simpler, but if you want scripting as well, NETCOMM.OCX works in VBS.
You can just write to COM1, but the VBA file system object has trouble with binary, and with reading. And NTFS used the same syntax for creating forks in the file system that BASIC used for configuring COM ports. (And MS never implemented a pseudo file system fork to restore the missing function, which they could easily have done). As a consequence, you effectively either have to use a comm object or the Windows API.

When and why do you need to use PtrSafe [duplicate]

This question already has an answer here:
32bit vs 64bit Office - Ptrsafe function delcaration - when can I use it
(1 answer)
Closed 1 year ago.
I would like to know how you know whether you even need to declare PtrSafe in your Microsoft Access database for an ACCDE to work on a 32-bit version of Microsoft Access. To my knowledge, I do not have any statements with the word Declare in them. My database has tons of subs and one global dim variable in a few forms, but that's it. I recently had someone unable to open my ACCDE file, and he got a 64-bit message error, but I have no idea even where to find which code is giving him issues. I'm not an expert with Access or VBA and don't quite understand when the PtrSafe statement needs to be used or not used.
UPDATE: the problem wasn't PtrSafe. The problem was that the file was an accde. The accdb file is bit agnostic, as long as PtrSafe rules are followed or no declare statements are used, but the accde has a bitness, meaning if it's compiled on a 64 bit version, it will only open on a 64 bit version.
===================================================
You'll need to use PtrSafe if your code will ever need to execute on a 64 bit version AND you are using DECLARE statements to interact with the Win32.api. See the section on api compatibility in the second link for more.
https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/ptrsafe-keyword
https://learn.microsoft.com/en-us/office/client-developer/shared/compatibility-between-the-32-bit-and-64-bit-versions-of-office

Using mouse events in vbscript, how to declare routines [duplicate]

Using visual basic in say Excel, I am able to declare WinAPI functions using the DECLARE keyword - e.g.
Declare Function SetLocaleInfo Lib "kernel32" Alias "SetLocaleInfoA" ( _
ByVal Locale As Long,
ByVal LCType As Long,
ByVal lpLCData As String
) As Boolean
However when using this syntax in a *.VBS file - it fails with a compile error.
Can anyone tell me what I need to do to run WinAPI functions from *.VBS files?
You can't run WinAPI functions from VBScript without some extra third-party support.
I believe there used to be vendor of a COM component which allowed VBScript to call into a standard dll but I can't remember what it was called and its quite possible that my imagination is playing tricks on me.
Plenty of forum posts mention 'dynacall' as the wrapper I think you're talking about however the two main links they post seem defunct
For what it's worth HTA may be worth looking at as an easy to use substitute
http://www.microsoft.com/downloads/en/details.aspx?FamilyId=231D8143-F21B-4707-B583-AE7B9152E6D9&displaylang=en

Lotus Domino on 64 bit system: Could not create automation object, error 208

I have created a C# .NET DLL with Release/AnyCPU as per http://www-01.ibm.com/support/docview.wss?uid=swg21230705 and successfully registered it for COM Interop.
When I open my 32bit Excel on a 32bit Windows 10, and use the code
Private Sub CommandButton1_Click()
Dim obj As Variant
Set obj = CreateObject("MyTest")
MsgBox obj.AppendStr("This is")
End Sub
it returns the expected values. When I open 32bit Excel on a 64 bit Windows 8.1, and use the same code, it also returns the expected values. The same goes for a similarly crafted VB6 executable deployed on both systems.
But when I try the same from Notes 32 bit using the code
Sub Click(Source As Button)
Dim obj As Variant
set obj = CreateObject("MyTest")
MsgBox obj.AppendStr("This is")
End Sub
it returns the expected values on a 32 bit Windows 10
it throws the error "Could not create automation object" on a 64 bit Windows 8.1
Furthermore, and this is the most interesting part for me, it throws "Could not create automation object" when run as a LotusScript http agent on the Domino 64 bit server on a 64 bit Windows Server system.
Do you have any ideas how I could get the DLL function call to work with both 32 as well as 64 bit Lotus Domino Server?
Or are there any other ways to call a single function in my C# DLL from Notes, which takes a single string as parameter and returns a byte array? (e.g. through a Java agent, through a Domino shell object, or both?)
I just found the solution, and it wasn't a Domino problem at all. The linked tutorial is for pre-64bit systems and says:
To make the objects in this DLL accessible via the COM interface, enter the following command:
regasm MyTest.dll
Since the introduction of AMD64, you have to read this step as follows:
To make the objects in this DLL accessible via the COM interface for both 32 bit and 64 bit applications, enter BOTH the following commands:
%Windir%\Microsoft.NET\Framework\<version>\regasm MyTest.dll
%Windir%\Microsoft.NET\Framework64\<version>\regasm MyTest.dll
I only did the first, which made it work for 32bit, but not for 64bit.
To answer the question in a technical aspect, you can call yout 32 bits DLL by copying it to Windows\SysWow64.see Can a 64 bit EXE link against 32-bit DLLs? for more details.
To answer your need we just need to transform a string to byte array.
You can do this in java and use ls2j to call it.
I also think to use the lib of native consumer to dothis.
Look also at https://www.experts-exchange.com/questions/23120423/Using-NotesStream-to-convert-a-string-to-a-byte-array.html it give you a lotuscript solution.

How does GetProfileString function look for values in the registry?

I was trying to get the default printer through VBA and I came across the Windows API GetProfileString function:
GetProfileString documentation
On one website I found a working example that retrieves the printer name:
returnedChars = GetProfileString("Windows", ByVal "device", vbNullString, printerName, Len(printerName))
The site I linked states that on Windows Server 2003, Windows XP and Windows 2000 (and later versions as well, I assume - the documentation probably isn't up-to-date) the values that GetProfileString return may be taken from the registry if certain conditions are met. I opened the Registry Editor and found the correct section - ...\IniFileMapping\win.ini\Windows. To my surprise, there is no key named device. I re-read the documentation a couple of times, but it didn't help. I don't have a corresponding section in my win.ini file.
Can anyone explain how this function exactly works? It looks like it could come in handy in numerous situations, so it would be nice to know how to use it properly.
This function is one giant backwards compatibility shim. The idea is for legacy code to continue working by picking up values that were moved to the registry when Windows moved from 16-bit to 32-bit.
The documentation makes this pretty clear:
Note This function is provided only for compatibility with 16-bit Windows-based applications, therefore this function should not be called from server code. Applications should store initialization information in the registry.
The message is clear. Do not use this function.
You ask how the function works, when it reads from the registry. That is covered in some detail by the documentation and I don't think there's much to be gained by trying to re-phrase that documentation.
It would be nice to know how to use it properly.
Use the function properly by never calling it!