GetWindowsDirectory() API returns wrong (vba\vb6) - vba

on my Windows-Terminal user, I'm trying to have two application point to the same Windows directory, one written in VBA one in VB6.
When calling the GetWindowsDirectory() API from VB6 it returns the correct path
C:\documents and settings\%user%\Windows
When calling it from VBA macro, it returns
C:\Windows
Notice that same result goes for GetSystemWindowsDirectory()
Thiking may be the VBA code wasn't aware its a Terminal station, I called the GetSystemMetrics(SM_REMOTESESSION) API which returned 1, meaning it is aware that it is a terminal.
The exact same code was used in both VB6 and VBA
Windows 2003R2 , Office version is 2010 64bit (which as i'm typing this, makes me wonder if it's related, knowing vb6 is 32bit ...)
Any ideas ?
EDIT: as explained by IInspectable below, the difference between vba and vb6 is because vb6 is not Terminal-Service-Aware like Office is.

The behavior you are observing is documented. See the Remarks section for GetWindowsDirectory:
Terminal Services: If the application is running in a Terminal Services environment, each user has a private Windows directory. There is also a shared Windows directory for the system. If the application is Terminal-Services-aware (has the IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE flag set in the image header), this function returns the path of the system Windows directory, just as the GetSystemWindowsDirectory function does. Otherwise, it retrieves the path of the private Windows directory for the user.
The DUMPBIN tool with the /HEADERS option can be used to verify, whether the IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE flag is set for a binary.
dumpbin /HEADERS WINWORD.EXE
produces the following output (Microsoft Office 2013 32-bit):
OPTIONAL HEADER VALUES
10B magic # (PE32)
...
2 subsystem (Windows GUI)
8140 DLL characteristics
Dynamic base
NX compatible
Terminal Server Aware
...
In other words: Microsoft Office is Terminal-Services-aware, and calling GetWindowsDirectory from a VBA script hosted inside Microsoft Office will return the shared Windows directory for the system.
If you checked your VB6 application with DUMPBIN, you'll see that it isn't Terminal-Services-aware, and calling GetWindowsDirectory will return the private Windows directory for the user.
Additional resources:
/TSAWARE (Create Terminal Server Aware Application)

Related

Apache/Perl Cannot Find MDAC without CommonProgramFiles(x86)

I am having a problem with using Apache/Perl to get access to Excel files using Microsoft Data Access Component (MDAC). Somehow I must set the "CommonProgramFiles(x86)" system environment variable in order to get this to work. Otherwise, I keep getting this error message:
System.InvalidOperationException: The .Net Framework Data Providers
require Microsoft Data Access Components(MDAC). Please install
Microsoft Data Access Components(MDAC) version 2.6 or later. --->
System.IO.FileNotFoundException: Retrieving the COM class factory for
component with CLSID {2206CDB2-19C1-11D1-89E0-00C04FD7A829} failed due
to the following error: 8007007e.
The server configuration is:
Windows Server 2008 R2 in 64-bit
Server is installed with Microsoft Access Database Engine 2010
Apache 2.2.25 (that is 32-bit)
Perl 5.12.3 v5 (that is also in 32-bit)
I have my Perl CGI script to call my C# program (that is built for "Any CPU").
The C# program uses MDAC to open and read Excel files (not trying to launch Excel, only try to read data from the Excel files).
I have verified that the server has the latest MDAC available in these 2 folders:
C:\Program Files\Common Files\System\Ole DB
C:\Program Files (x86)\Common Files\System\Ole DB
I have also checked the registries and they look fine. Anyway, I don't have any problem running my C# program directly at the command prompt (it can use MDAC to get access to Excel files). I only have the problem when I use Apache/Perl to use my Perl CGI script to call my C# program (that is when I get that error with MDAC).
I can work around this problem by specifying CommonProgramFiles(x86) in my Perl CGI script, like this:
$ENV{ "CommonProgramFiles(x86)" } = "C:\\Program Files (x86)\\Common Files";
I have this question:
Why do I have this problem? And why setting that CommonProgramFiles(x86) system environment variable can workaround this problem? Why that system environment variable is empty before I set it? Does this have to do with the fact that I am running 32-bit Apache/Perl in a Windows operating system that is 64-bit?
Please help me to understand this issue. Thanks in advance.
(The original version of this post had a question about a second problem. Turned out that problem had to do with an extra double quote in the string. I fixed this, and that problem has gone away. That's why I have removed that second question from the post)
Jay Chan
I did some more research and the issue is the following: until release 2.4.9, the Apache startup routines have mapped "commonprogramfiles(x86)" to "commonprogramfiles_x86_" and that variable does not exists in the environment unless you create it... I have not tested it, but creating that environment variable and making it point to the same location as commonprogramfiles(x86) would probably fix the issue too.
Since the compiled Apache distributions are only using up to version 2.4.46 as we speak, they don't have the fix that allows the parenthesis in environment variables. That's why you still need the PassEnv directive to ensure that Apache passes the correct values to 32-bit CGI scripts.
The following post has some useful details about this:
https://bz.apache.org/bugzilla/show_bug.cgi?id=46751
I used to have the same problem in with Apache 2.4 with dBase compiled apps using ADO-32 bit as dBase is 32-bit. Something has recently changed, possibly with Windows 10 2004 20H2. I needed this fix in July-Aug 2020 but now I don't, the environment variable already exists. Since my Apache version is dated April 2020, that cannot be the reason for the change.
I tried to do some research about this but all I could find is that those environment variables are system ones existing at least since 2017, so why I needed to set this var is a mystery to me, but I would like to understand this, so if you find something, post a follow-up...
https://learn.microsoft.com/en-us/windows/deployment/usmt/usmt-recognized-environment-variables

This .asp file need some dll that my windows server 2003 64bits dont have

When i try to run these .asp code https://drive.google.com/file/d/0Bx1hNT8CEtf6cUFjYlJia2JBUGM/edit?usp=sharing
i have the following error message: https://drive.google.com/file/d/0Bx1hNT8CEtf6dno3ajBpanl2OXc/edit?usp=sharing
The site is running on a Windows server 2003 64 bits, i have done a search on internet and look like is some dll missing, can i discovery what dll just with this code ?
Your file is a classic ASP file, not an ASP.NET file. Line 99 has this line of code:
Set objCrip = Server.CreateObject("Criptografia.Cripto")
Criptografia is usually the name of the DLL and Cripto is the name of the object inside of it. You can perform a search on your hard drive for Criptografia to see if it exists or search your Registry for the full name Criptografia.Cripto to see if there is a different DLL associated with it.

VB6 COM Object - only works when IDE is running?

I have an ancient COM object in VB6 that has been working fine until recently. (Don't they all). The only code change that has been made (as verified by svn) is the inclusion of a new string literal in an array.
The VB6 IDE compiles the object fine. When I hit Run|Start... and execute the following test vb script from the command prompt, the object works fine and I see the dialog boxes I expect:
dim o
set o = CreateObject("MyDll.MyClassName")
wscript.Echo "Testing object"
wscript.Echo o.HelloWorld ' runs a test method that returns "Hello World"
wscript.Echo "Done"
However, when I stop debugging in the IDE and attempt to run the same vbscript from the same command prompt, I get the error:
(ProgID removed for security reasons, but it is the same as in the script.)
Things I've tried:
I suspected that the DLL may have been registered and unregistered by VB when I start and stop the debugger, so I also tried registering the object with regsvr32 before running the test script. This has had no effect.
I also removed all references to the DLL from the registry, and re-registered the object. Same error.
I deleted the DLL and re-built it from VB (File|Make...) and re-registered the DLL. Same error.
Machine is Win7 Ultimate x64, object built with VB6.
Any suggestions?
And, no, unfortunately, rewriting the object in C# isn't an option.
Microsoft says it's some sort of dependency issue: http://support.microsoft.com/kb/194801
Because it's working when you run the object in the IDE this leaves you with four possibilities:
The ActiveX dll itself is not on the system path.
The ActiveX dll depends on something else which is not on the system path.
After registering the dll, it is somehow marked as requiring elevated security to run
After registering the dll, something it depends on requires elevated security to run.
I would try opening a command prompt as administrator then run your vbscript file that starts the object. If that works then it means the problem is either #3 or #4. If it doesn't, then it means #1 or #2.
You can eliminate #2 and #4 if the ActiveX dll has no external dependencies.
Next, I'd look in my event log to see if any other errors were logged by windows about this.
UPDATE
Just found another possible cause. If the ActiveX dll is 32-bit, then the script has to use the 32-bit version of the script engine to run; otherwise it will give this error because the default script engine (x64 on that machine) literally can't find the dll.
I believe if you use \windows\system32\cscript.exe to run your vbscript then you'll be good.
Well it definitely sounds like the issue because of 32bit dll.. The suggestion mentioned above is correct but the path is wrong.. try using the CSCRIPT from C:\Windows\SysWOW64..
Try registering the DLL with regsvr32.exe from %Windows%\SysWOW64. It is different than the regsvr32.exe in %Windows%\System32 (on a 64-bit OS).
See this SO posting.

Microsoft Office Excel cannot access the file

I have create Office Excel application in my machine(XP). and i have placed the application in windows server 2008 giving the following error.
Microsoft Office Excel cannot access the file '\server\Input.xls'. There are several possible reasons:
The file name or path does not exist.
The file is being used by another program.
The workbook you are trying to save has the same name as a currently open workbook.
both client and server systems installed office 2007 and added reference microsoftexcellibrary 12.0
created assembly for the application and calling the code from the form.
I was getting the exact same error, although in my case I was trying to run (from Tidal Enterprise Scheduler) a .NET app that used microsoft.interop.excel.
The answer is already in stackoverflow:
[Microsoft Office Excel cannot access the file 'c:\inetpub\wwwroot\Timesheet\App_Data\Template.xlsx'.
I'll re-list the steps from that link:
Create directory “C:\Windows\SysWOW64\config\systemprofile\Desktop” (for 64 bit Windows) or “C:\Windows\System32\config\systemprofile\Desktop” (for 32 bit Windows)
Set full control permissions on Desktop directory above (for example in Win7 & IIS 7 & DefaultAppPool set permissions for user “IIS AppPool\DefaultAppPool”)
Of course, if you're running a scheduled task rather than WebApp, you'll need to make sure the service account you're using has permissions on that folder.
I had the same error when trying to save to:
C:\test.xlsx
When attempting to save to the root directory, it seemed to cause problems. Changing my path to:
C:\MyExcelTests\test.xlsx
Worked fine
I would make sure no Excel processes are running on the machine before you run this application, that should cover the last point.
The first point looks the most likely issue, the path looks like a partial path or an incorrect UNC path. Try putting the full path to the spreadsheet 'C:\server\input.xls' and see if that works.
To stop the middle point, in the workbook.open command you can specify to open as read-only, this will make sure the application can red the file even if it is locked open by another user.

How Do I Get The Resource DLL Code Samples In The Windows SDKs To Compile And Run?

I am currently trying to build a Resource DLL on on Windows Server 2003 and 2008. I am currently working with the Resource DLL code samples supplied with the Windows SDKs, and I can't get them to work.
On Windows Server 2008 I succeeded compiling the Windows 7 SDK ClipBook Server sample, but couldn't get it to properly work in the cluster. When I insert the resource as a resource type to the cluster using "cluster restype /create /dll" it works, but the resource is listed with an unknown type instead of a ClipBook Server type, as I think it should have as it is the type defined in the Resource DLL's code.
I also succeed in creating a resource of that type, but I can never get it to go Online. I always get the error:
System error 5079 has occurred (0x000013d7).
The specified node does not support a resource of this type. This may be due to version inconsistencies or due to the absence of the resource DLL on this node.
And this is despite the fact that the resource is located on all the nodes in the cluster including the one I try to start the resource on.
On Windows Server 2003, I'm working with the Platform SDK version 5.2, and I can't even get the ClipBook Server Resource DLL code sample to compile. I always get MIDL1001 Error saying that it cannot open the file cluscfgserver.idl. I added the path of the file's location to the include path of the project. That didn't work. When I tried to hard-code the path of the file, I got several linker errors when trying to link with this file.
If anyone knows anything about any of these problems, I would appreciate any input.
Those examples are old and busted. Here are a few things I had to go through to get the similar "File Share Sample" to work:
Convert the project to x64 (supposedly 32 bit resources still work, but I haven't been able to verify that)
Add the module definition file (.def) to the linker input property page so that the Startup function is exposed
There were several spots in code where CompareString is used to check the resource type name and 0 is expected on success, but it actually returns CSTR_EQUAL (3).
This is probably why you get the "(Unknown Type)" name.
To register the resource extension, cluster.exe won't accept spaces in the dll name, so in my case I had to use cluster /REGADMINEXT:'FILESH~2.dll'
Only the Property Sheet extension interface is supported, everything else (context menu, wizards) has been removed as of Server 2008
Check the extension DLL stdafx.cpp sources for the Resource Type "ClipBook Server". It should be "ClipBook Server Sample": const WCHAR g_wszResourceTypeNames[] = L"ClipBook Server Sample\0"