Does anyone have any idea why CoCreateInstance would be failing on ITaskBarList3 on Windows 7 64-bit? The error code is 0x80040154, which is Class Not Registered.
The calling code (VB6) is:
Public Const IID_ITaskbarList3 = "{EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF}"
Public Const CLSID_TaskbarList3 = "{EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF}"
'....
Dim IID As GUID_API
Dim CLSID As GUID_API
Dim iTaskBarVB3 As ShellLib.ITaskbarList3
rc = CLSIDFromString(StrPtr(CLSID_TaskbarList3), CLSID)
rc = IIDFromString(StrPtr(IID_ITaskbarList3), IID)
rc = CoCreateInstance(CLSID, 0, CLSCTX_SERVER, IID, iTaskBarVB3)
The returns from CLSIDFromString and IIDFromString are both 0 (Success). I can find the string in the registry. Since my taskbar is obviously working just fine, I know the interface is able to be called by other processes just fine.
ITaskBarList3 is declared in a typelib compiled using mktyplib.exe. I've double checked the GUID values, and they match those in the SDK.
Any help would be greatly appreciated.
The most likely reason is that the calling code is 32-bit and the COM server is 64-bit and therefore can't be loaded as an in-proc server.
A possible solution could be to create a COM+ application for the COM server to force its creation as an out-proc server. However this will not help if the COM server is meant to supply an ActiveX control.
I'm also surprised to see the class id being equal to the interface id - it's common practice to have them different. Since you are not the developer of the component implementing that interface but only the consumer it's likely that you just misplaced the class id with the interface id and this is the reason why your client program is not working. You should find the class id of the class implementing the ITaskBarList3 interface and use it as the class id.
CLSID_TaskbarList3 doesn't exist! It's simply,
CLSID_TaskbarList = "{56FDF344-FD6D-11D0-958A-006097C9A090}"
which indeed has a different GUID than the IID_TaskbarList3 IID.
In COM you have typically one class implementing one or more interface. There doesn't generally exist a new class for every interface.
The ClassID wasn't the problem, as this worked correctly about a week ago. I was previously compiling on Windows Vista, 32-bit.
I've now updated my system to Windows 7, 64-bit. The problem isn't a matter of 32/64-bit compatibility. The TaskBar is accessible through Wow64, and I am able to call the interface just fine from a 32-bit ATL DLL.
I did some more searching, and I found a number of references on the web regarding problems with actxprxy.dll on 64-bit windows. This is the DLL where the interfaces appear to reside, according to OLE Viewer.
Anyways, some people have had luck with various combinations of .reg scripts and unregistering/re-registering the files. Unfortunately, I'm not one of those people.
I've decided to save myself the headache, and just wrote a small DLL using ATL, and I have the VB code calling that. Works fine in that setup...
Thanks again for your help.
Related
I'll try to be brief: We have code written in Visual Basic 6.0 that I am trying to compile on a Windows 7 64-bit computer. (Previously this was compiled on an old XP computer.) Most of the code seems to compile correctly, however certain code that has Attributes, like the NewEnum, are not honoring the VB attribute. Here is an example:
The VB6 method looks like this:
Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Attribute NewEnum.VB_MemberFlags = "40"
'this property allows you to enumerate
'this collection with the For...Each syntax
Set NewEnum = mCol.[_NewEnum]
End Property
This is default Enumerator that is created when you use the Class Builder Utility.
However, the Attribute elements are not honored when the code is compiled. Using the OLE View program, it shows that the Attributes are ignored.
The XP computer produces the following snippet:
[id(0xfffffffc), propget, hidden]
HRESULT NewEnum([out, retval] IUnknown** );
But the Windows 7 computer generates:
[id(0x68030000), propget]
HRESULT NewEnum([out, retval] IUnknown** );
I have attempted to set the Visual Basic application to run in XP (Service Pack 3) Compatibility mode and this has not helped.
Because of the size and complexity of our application we cannot port it from VB6 to .NET at this time, and we need to get it to compile. Does anyone know how to properly configure VB6 so that it will properly compile a collection?
I'm running an app for testing students, which prevents them from doing anything but the test.
Naturally, the app blocks them from closing it, and blocks them from running the task manager (among other things):
[DllImport("WinLockDLL.dll")]
private static extern int CtrlAltDel_Enable_Disable(bool bEnableDisable);
private void Restrict(bool enabled)
{
CtrlAltDel_Enable_Disable(enabled);
}
The dll contains other functions I use, such as hiding the taskbar and the desktop.
Until recently, the students all had WindowsXP, and it worked.
Recently the students have all upgraded to Windows7, and it stopped working.
During debugging, I've found that Windows7 simply doesn't HAVE WinLockDLL.dll, so I copied the dll to one of the W7 computers and gave the app a try.
This time it found the dll and raised no errors, but the function simply had no effect.
So, does anyone know of an alternative in Windows7?
The closest thing I found was this, in which someone posted that:
All the functions you used in the example crash on Windows 7 unless you change the call to DLL_CALL_STDCALL
"Calling STDCALL" doesn't help, since that is exactly what DllImport does by default.
I've read of alternatives for blocking ctrl-alt-delete, such as canceling the ctrl key or blocking the taskmanager via registry or GPO, but I much prefer a simply alternative for WinLockDLL.dll, which contains several functions I use.
Thanks in advance!
For anyone that finds this in the future. I am creating a library to replace WinLock.dll for Windows 7. The source can be found here.
Win7Lock Github
I try to create a COM object from my JS script like this:
function main()
{
var MyApplication = new ActiveXObject("Base.Application");
}
main();
I am getting error: "Automation server can't create object". This error occurs on Windows 2003 64 bit. The dll is 32 bit and it works fine on 32 bit systems.
I've tried both versions of Regsvr32.exe on the 64 bit system and both versions told me that dll registered succesfully.
Unfortunatelly the error message does not tell me why it can not create object. The reason is unknown, it might be that it can't create object because it is still not registered or it might be something totally different...
I've also add full permisions to this dll.
I don't know what else I can do, do you have any ideas?
After edit
Ok, I know that this DLL is registered under system (found it at the registry), so why I can't call any COB objects from it?
Maybe because your process is 64 bits and you try to call in a 32 bit dll? (There are some tricks though, in this case like the one described here).
I've implemented my own Microsoft Search IFilter. I need two versions of it - 32-bit and 64-bit for deploying them on corresponding systems.
In case of IFilters for any file extension I can only register one IFilter class id. Which means I can only use one version on any system. So having two class ids seems useless - it only makes the automatic installer more complex.
Do I reuse the same COM class id for both or do I use different class ids?
Always use a different CLSID. Dont reuse COM CLSID. You can make them both use the same IID, but always different CLSID.
We ended up reusing the same class id for both versions - since 32-bit programs on Windows 64 see their own copy of HKCR there's no conflict and the same class id is mapped to the right executable in both 32 bit and 64 bit programs. The COM server uses ATL and using the same class id greatly simplified the .rgs registration script.
My boss just got Windows 7 and he tried running one of our installers which runs perfectly fine under XP. On Windows 7, the installer runs without giving any errors. However, it does not create registry keys under HKEY_LOCAL_MACHINE\SOFTWARE{Company}{product}. These keys get created correctly under XP.
Has anyone encountered this issue? I suspect it is a rights/security issue but I'm not sure and I don't have Windows 7 to experiment with.
EDIT
The computer in question is a 64-bit machine running 64-bit Windows. It turns out Windows 7 redirects 32-bit applications to HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node{Company}{product}. The problem is my application code tries to access the registry using a hardcoded value like this:
var t = Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\..., "ValueName", DefaultValue);
So, my new question is how do I access the registry such that the Windows 9 registry redirection will just work?
If you're using .NET 4, you can specifically request that your 32-bit (or 64-bit) process access the 64-bit view of the registry using the RegistryKey.OpenBaseKey method.
Cf. http://msdn.microsoft.com/en-us/library/microsoft.win32.registrykey.openbasekey.aspx
Here's an example that reads a value from the 64-bit view of the registry, even if it runs as part of a 32-bit process:
var hklm64 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var key = hklm.OpenSubKey(#"SOFTWARE\AcmeSoft\AnvilMaker 1.0");
var value = (string) key.GetValue("Blacksmith Name");
The RegistryKey.OpenBaseKey method also allows you to explicitly open a 32-bit view of the registry. This is useful if you're trying to go the other way around and access the 32-bit view of the registry from a 64-bit process and you don't want to explicitly add "Wow6432Node" to the registry path.
For example, today I needed to delete a sub-key tree in both the 32-bit and 64-bit views of the registry. Doing this in .NET 4 with a single registry path was easy:
foreach(var view in new[] {RegistryView.Registry32, RegistryView.Registry64})
{
var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view);
hklm.DeleteSubKeyTree(#"SOFTWARE\AcmeSoft\SomeKeyWeNoLongerWant", throwOnMissingSubKey: false);
}
On a 64-bit version of windows, the above code will remove the following sub-key trees from the registry:
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\AcmeSoft\SomeKeyWeNoLongerWant
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\AcmeSoft\SomeKeyWeNoLongerWant
-Adam
After more digging I came across this link which describes the registry access rules for .NET applications. My program had initially been targeted for "AnyCpu" which causes the app to target the 64-bit registry even though Windows installed it under the Wow6432Node. By setting the target to "x86" my program "magically" started accessing the registry under the Wow6432Node. Go figure!
In the C Windows API this is done by setting the samDesired parameter in the RegOpenKeyEx call to KEY_WOW64_64KEY. This means that the lookup of the registry value will map onto the regular 64-bit entry, rather than the WOW32Node one. I can't see how you would achieve this in .Net though as the Registry class doesn't appear to support these operations, but maybe it's provided through a newer class?
Registry Reflection
Code Sample