Windows Scripting can't find reference - com

I have a windows script file that doesn't work anymore.
The script look like this
<job>
<reference object="Some.Component.1" />
<script language="VBScript">
x = CreateObject("Some.Component.1")
MsgBox TypeName(x)
</script>
</job>
When I run the script with cscript or wscript I get the error
Windows Script Host: Cannot find the type library for this reference :
Some.Component.1
The error code is 0x80040068 which means "Invalid index". (I tried to removed the .1 index but it didn't work)
The strange thing is that if I remove the line <reference object="Some.Component.1"/>, the CreateObject line works and the object is created.
I know the script worked about a year ago. The "Some.Component" library has been updated but since CreateObject works I have no idea what is wrong with it.
I have tested the script on Server 2008 R2 (64bit), Server 2003 (32bit) and Windows 7 (64bit) with the same error.
Some.Component is 32 bit. For the 64bit machines I used cscript, wscript in the SysWow64 folder.
(I need the <reference../> to access enums within the component)

The type library is not registered. This is a different and separate thing from the object being registered. Usually the control will do both.
I suggest you first try unregistering and re-registering the DLL.
regsvr32.exe /u c:\path\to\control.dll
regsvr32.exe c:\path\to\control.dll
If that doesn't work, try using RegTLib.exe to register the type library (*.tlb) directly.
regtlib.exe c:\path\to\control.dll
OR
regtlib.exe c:\path\to\control.tlb
Note that the type library may be a separate file or may be embedded in the DLL.
For more on regTLib.exe see here:
http://support.microsoft.com/kb/292744

Related

GetWindowsDirectory() API returns wrong (vba\vb6)

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)

AnyCPU COM library (.tlb file) not working when called from external VB6 macro in x64

Okay my title might not be clear enough. I work with an application for which we can develop VB6 macros. This macro needs to work with a .NET dll that I also developped. When I launch the application in x86 mode and I try to run the macro, it's working fine, I can access the methods of the class and everything.
But when I do the same in x64 mode I get the error : "Automation server can't create object"
What's really strange is that I'm not using any x86 unnmanaged COM dll which would be a problem with an x64 architecture. When I do : "Dim myClass as new MyClass.App" it's working but when I call for example a myClass.Start() method, I get this error. And I tried just having a MsgBox('hello world') in my Start method, to be sure it had nothing to do with my code, still no luck. I'm linking my macro to my class with a TLB file.
I tried registering my DLL with RegAsm, but it's still not working in x64. Is there a way to generate both x86 and x64 versions of my TLB? Then I would add both references and if the x64 version throws me an error on Start method, I simply call the x86 method (not a perfect solution, but still..).
Any idea how to solve this problem?
As Hans said, I needed to user the 64-bit version of Regasm.exe. Even though I had already tried launching RegAsm manually after my installation, it was not working. First I added that in the post-build event of my project :
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe" "$(TargetPath)"
That did the trick for the Debug version. What's strange is that the AnyCPU version was working fine at first on my x64 application, in debug mode, it started crashing when I created my setup project (no idea why...). But this change doesn't solve my problem when installing the application, so I added this in the "Commit" of my custom action (based on this article : Regasm- 64bit or 32bit though windows installer in visual studio) :
Public Overrides Sub Commit(savedState As System.Collections.IDictionary)
MyBase.Commit(savedState)
'Check if we're on a x64 OS
If Environment.Is64BitOperatingSystem Then
'Get the Windows dir on the current computer
Dim winDir As String = New IO.DirectoryInfo(Environment.SystemDirectory).Parent.FullName
'Define the path to regasm for x64 machines
Dim regasmPath As String = IO.Path.Combine(winDir, "Microsoft.NET", "Framework64", System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion, "RegAsm.exe")
If File.Exists(regasmPath) Then 'Si le chemin existe, on enregistre la DLL
'Get the location of our DLL
Dim componentPath As String = GetType(Installer).Assembly.Location
'Executes regasm
System.Diagnostics.Process.Start(regasmPath, "/codebase """ & componentPath & """")
End If
End If
End Sub
What I changed from the original article is the path to RegAsm. Since my setup is x86, the RuntimeEnvironnment's directory was pointing to the "Microsoft.NET\Framework..." path not the "Framework64" which was defeating the purpose of my action (it was already registered as a 32 bit COM interop), so I try to get the x64 version of RegAsm and run it.

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

VBS - Register and use Dsofile Windows 7 64 bit

I'm trying to use Dsofile with a VBS script on a Windows 7 64-bit machine. I believe my issue is with registering the DLL.
I used this to register the DLL
regsvr32 D:\Desktop\dsofile.dll
and am told that
"DllRegisterServer in D:\Desktop\dsofile.dll succeeded."
leading me to believe that everything worked. When I try to run the test code that Microsoft gives
Set objFile = CreateObject("DSOFile.OleDocumentProperties")
objFile.Open("D:\Desktop\test.xls")
Wscript.Echo "Author: " & objFile.SummaryProperties.Author
it fails on the first line, stating that
"ActiveX component can't create object: 'DOSFile.OLEDocumentProperties"
which leads me to believe that the DLL did not actually register correctly.
I then tried registering the DLL, based off this solution, by doing the following
cd \Windows\SysWOW64
regsvr32 C:\dsofile.dll
It also informs me that it registered correctly, but once again the script fails on the first line.
How can I fix this, so that I can use Dsofile?
Thanks.

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.