OleCreate fails with E_CLASSNOTREG when compiled with 64-Bit (C++) - c++

I am trying to display a new Word document inside a Widget, using OLE. This works fine as long as I compile my application under x86 architecture. Now I tried porting my application to x64 and it stopped working. The call to OleCreate() fails with REGDB_E_CLASSNOTREG.
CLSID clsID;
IUnknown* pIUnknown;
HRESULT res = CLSIDFromProgID(L"Word.Document.8", &clsID);
if (SUCCEEDED(res)) {
res = OleCreate(clsID, IID_IUnknown, OLERENDER_DRAW, NULL, NULL, storage, reinterpret_cast<void**>(&pIUnknown));
}
After some research I came across some solutions, but none of them were applicable.
I can't set my compiler to x86 when I'm trying to port my application to x64 so following Post hasn't solved my problem.
I tried calling regsvr32.exe withC:\Windows\System32\ole32.dll but it didn't change the result.
I tried installing the hotpatch, which was shipped by microsoft to fix the same problem with OleCreateFromFile(). Sadly it doesn't fix the problem for OleCreate() - hotfix
The only solution, which worked so far was to copy the content of HKLM\SOFTWARE\SysWow64\Classes\CLSID\<CLSID of Word Document> into HKLM\SOFTWARE\Classes\CLSID\<CLSID of Word Document> but this is more of a hack than a fix, because I would have to modify the registry of every machine on which I want to run my application. Since this task requires administrator privileges, I can't do this from inside my application.
I need a solution which works and doesn't force me to manually alter registry entries.
I'm running my application on a Windows 7 Professional SP1 64-Bit machine with a 32-Bit Office 2010.

After some more testing I found the solution to the problem, which was to use Word.Document instead of Word.Document.8 as progID.
I have don't know why this seems to be a problem with 64-Bit compilation. The thing, I noticed though was that CLSIDFromProgID() now resolves to a different CLSID.

Related

Missing registry key for IUIAutomation

I'm trying to use the UI Automation sample on msdn located here;
https://code.msdn.microsoft.com/windowsdesktop/UI-Automation-Document-24a37c82#content
i keep getting the error message: REGDB_E_CLASSNOTREG Class not registered
The Microsoft example uses this line to create an instance of the CUIAutomation8;
CoCreateInstance(__uuidof(CUIAutomation8), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&_automation));
which is the part it seems to be failing at, from digging around this seems to be getting the id of the class and then checking the registry key at that location ({E22AD333-B25F-460C-83D0-0581107395C9} in this case) however my machine doesn't have this key already entered which i think is causing the error, i'm not sure if i'm having to install anything extra that i'm currently missing? As of now all i've done is download the sample and tried compiling it
any help would be much appreciated!
note: I'm using windows 7 with SP1 and VS2015
i've also tried changing CUIAutomation8 to IUIAutomation instead but i'm getting the same issue but as a different registry key
CUIAutomation8 is documented to need Windows 8 or higher for Windows 7, you want to use CUIAutomation

midiOutOpen on Windows 10 using Microsoft GS Wavetable Synth fails

I have an application that relies on the in built Microsoft GS Wavetable Synth. It has worked flawlessly on Windows XP, Vista, 7, 8 and 8.1. While the first call to midiOutOpen on Windows 10 works, subsequent calls result in error code 1, meaning 'Unspecified error'. The code is simple:
result = midiOutOpen(&_midiOutHandle, midiOutputDevice, NULL, 0, CALLBACK_NULL);
Any ideas regarding how to resolve this hugely appreciated.
I see it. Tracing through the machine code, I see the modMessage() function fail and return MMSYSERR_ERROR. Exactly why isn't clear to me, it looks like a missing initialization problem.
What is strange about this mishap is that there are not a lot of complaints about it, you'd expect plenty of other programs fall over as well. Or for that matter for them to be tested before Win10 shipped. Next thing I tried is adding the one thing that happens in any non-trivial audio app that I skipped in my test program. Partly inspired by seeing "ATL" back in the symbols of modMessage, although it wasn't anywhere close. I added this as the first line in main():
CoInitializeEx(NULL, COINIT_MULTITHREADED);
Badaboom, no more error. Use COINIT_APARTMENTTHREADED if you call this on the main thread of a UI thread. CoUninitialize() at the end to clean up.
Explaining it is difficult, initializing COM should not be necessary when you use MIDI. With it in place, calling midiOutOpen gets one more DLL loaded, clbcatq.dll. That's a COM+ support module. So sure looks like Win10 requires COM to be initialized.
I put a MessageBox (with nothing important to say) just before midiOutOpen, and IT WORKED!
I'm using Visual Studio 2013 C++.
WASAPI doesn't work for me anymore in sharing mode, although I think I'll be able to make it work.
When I use the CoInitializeEx(NULL, COINIT_MULTITHREADED), this helps for the midi open problem but has bad influence for using mciSendString with opening an MP3 song, which results always in error 266 in same program. Eg.:
open "d:\\music\\Fernando.mp3" type MPEGVideo alias Fernando.mp3 wait
(without the CoInitializeEx this open works and the mp3 song plays in Windows 10).
On some Windows 10 Systems the midi and mp3 open well without calling the CoInitializeEx, on others it does not play midi. It is not documented in MCI api that it must be called and causes indetermined problems. For me it is not clear when or why it must be called and when I should better not call it.
The Windows 10 incompatibility relating MCI of Microsoft is intolerable.
All Systems since XP are MCI compatible and only Windows 10 causes troubles.

COM Codebase Location - How to pick which version to use?

I have needed to modify code in a C# DLL and use it within a C++ application. I am not savvy at all in C++, so if something isn't clear let me know.
I've registered the C# assembly using:
regasm file.dll /tlb:file.dll /codebase
However, when I try to use this in the c++ application:
CLSID clsid;
CLSIDFromProgID(L"MyApp.MyClass", &clsid);
HRESULT hr = CoCreateInstance(clsid,NULL, CLSCTX_INPROC_SERVER ,IID_MyClass, reinterpret_cast<void**>(&myclass));
hr returns with 0x8013151a: access to this member is denied
I've noticed that in registry, I see multiple versions of the C# dll (with Codebase pointing to different dll locations).
I think the problem is because it's not using the correct dll. (I could be completely wrong).
My question is this, how do you know which version of the dll it's trying to load?
Thanks in advance.
Pretty unlikely that this is a DLL Hell problem. You can double-check by using the debugger's Debug + Windows + Modules window, it shows you the path of the DLL. Keep your registry clean by letting MSBuild register the component, Project + Properties, Build tab, "Register for COM interop" option. VS must run elevated.
This is a MethodAccessException, always a coding bug. Psychic debugging required without seeing your code but the simplest explanation is that your C# class' default constructor is not public.

How can we unit test our c++ COM code without registering the dlls?

We are trying to add unit testing to out legacy c++ COM application. We also need our build machines to be able to runt he unit tests to ensure each build hasn't introduced errors. However we don't want the build machines to have to register the com dlls so that one build machine can build multiple versions in parallel.
We assumed that we could change to using registration free com with manifest files, but i am having a very difficult time getting that to work. Not on our code base yet but just on the basic example provided by Microsoft.
I've been using this page http://msdn.microsoft.com/en-us/library/ms973913.aspx#rfacomwalk_topic8
and it simply won't work, when i try to run with the dll unregistered to use the manifest files, i get the "Class not registered error"
The samples they provide work fine (using c++ com server and c++ client), however when i rebuild them they don't work.
We are using Visual Studio 2013 and so it looks to me like there has been a large change in the way that registration free com works, which makes this tutorial incompatible with the newer compiler.
Can anyone point me to resources on using registration free com with the latest version of visual studio? To further complicate things in our own app when i get there we are using VS 2013 but targeting the 2010 compiler, hopefully that won't make to much difference.
Also if there's a better way of running c++ unit tests on com components without registering than manifest files i would like to hear about those as well.
Thanks for your help.
Probably too late for the OP but for anyone else that comes across this question, there is an article by Samuel Jack on this here... which may or may not help future readers...
See http://blog.functionalfun.net/2012/09/a-quick-guide-to-registration-free-com.html
You could implement your own version of CoCreateInstance that take an extra DLL path parameter. The code would be something like this (error handling and other details omitted for brevity):
HRESULT CoCreateInstanceForTest(dllPath, rclsid, riid, ppv)
{
HINSTANCE hinst = LoadLibrary(dllPath); // TODO: Maybe it is already loaded
dllGetClassObject = GetProcAddress(hinst, "DllGetClassObject");
return dllGetClassObject(rclsid, riid, ppv);
}
Besides error handling, you also need to keep track of the DLLs you already loaded. Use a list or array in which each element has a tuple to track this. At some point you might want to unload all or some of them.
Of course, I am assuming these are inproc COM servers.

SHDocVw::IShellWindowsPtr fails with IE8? (Error 0x80040154)

My program is a dll that hooks into a running instance of IE. It's worked fine for years.
Recently I dusted it off and ran it, but the last line below fails with hr = 0x80040154:
#import <mshtml.tlb> rename("value", "theValue") rename("event", "theEvent")
#import <shdocvw.dll>
// ....
SHDocVw::IShellWindowsPtr spSHWinds;
HRESULT hr = m_spSHWinds.CreateInstance(__uuidof(SHDocVw::ShellWindows));
Could it matter that IE7 has been replaced by IE8? Where else should I look?
I'm using VS2008, if that matters.
Edited to add
I don't see that it could be a 32/64 bit issue - it ran fine last year on this same machine. The only thing that's changed (as far as I have noticed) is the version of IE, from 7 to 8.
Note to the bounty hunters:
I only have access to this system for a few hours a day (around 0:00 EST), so you may not get quick responses to your suggestions, but I will look into them.
If you think there are things I should be checking (registry values, for example), be specific.
Edited to add:
I now see that the first time I call CreateInstance, it returns 0x80070002, not 0x80040154.
That's going to be very hard to diagnose. The ShellWindows coclass is special, its CLSID registry key is HKEY_CLASSES_ROOT\CLSID\{9BA05972-F6A8-11CF-A442-00A0C90A8F39}. When you look there, you'll see nothing useful registered there. The background story is that this is a leftover of an ill-fated attempt to make the Windows shell resemble a web browser. Still visible today, enumerating the shell windows returns both Windows Explorer and Internet Explorer instances.
The SysInternals' ProcMon utility is almost always the weapon of choice to debug 0x80040154 errors but it falls flat here. You can see it probing the registry, and not finding what it is looking for, but then the program knows how to load ieframe.dll anyway. This can only work by the operating system intercepting the CoCreateInstance() call. Which makes sense in general, considering the coclass enumerates shell windows.
All you got left is the trial-and-error approach. Reinstall IE first, OS next. Or to shove the machine out of a 4th story window before it eats too much of your valuable time.