Thread: COM and IActiveDesktop

  1. #1
    Registered User dalek's Avatar
    Join Date
    May 2003
    Posts
    135

    COM and IActiveDesktop

    Hi all,

    Just trying to write an application that plays with the desktop under windows XP. I need to use the COM interface IActiveDesktop and I have found plenty of examples, however I cannot compile them.

    I keep getting this error. Searching for this error returns very little information - Anyone got any ideas?
    c:\Program Files\Microsoft Visual Studio .NET\Vc7\atlmfc\include\atlcomcli.h(451): error C2787: 'IActiveDesktop' : no GUID has been associated with this object
    Cheers

    (By the way - that is using XP and Visual C++ Standard 2002).
    Last edited by dalek; 04-14-2004 at 04:21 AM.

  2. #2
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    A line of code could be helpful! Anyway, the magic of Google:
    http://support.microsoft.com/default...b;en-us;192561

  3. #3
    Registered User dalek's Avatar
    Join Date
    May 2003
    Posts
    135
    Thanks - read the article but it doesn't appear to be the same problem.

    I cut and pasted the code that Fordy posted as an answer some time ago to a question regarding IActiveDesktop. The code is below copied directly from the other thread.

    Code:
    #include <windows.h>//Essential stuff
    #include <wininet.h>//This has to be here...bug!!!!!!
    #include <shlobj.h>//For IActiveDesktop
    #include <comdef.h>//For neat VC++ COM Classes
    
    
    
    struct COM_INIT{//To manage COM
    	COM_INIT(){CoInitialize(0);}
    	~COM_INIT(){CoUninitialize();}
    }COM_INIT_;
    
    int WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR,int){
    	
    	char szFile[MAX_PATH+1] = {0};
    	OPENFILENAME ofn = {sizeof(OPENFILENAME)};
    	ofn.hInstance = GetModuleHandle(0);
    	ofn.lpstrFilter = "BMP\0*.BMP\0JPeg\0*.JPG\0Gif\0*.GIF\0";
    	ofn.lpstrFile = szFile;
    	ofn.nMaxFile = MAX_PATH+1;
    	ofn.lpstrTitle = "Pick Bitmap, JPeg or Gif to replace wallpaper";
    
    	if(!GetOpenFileName(&ofn))return 0;
    
    	try{
    		
    		WALLPAPEROPT wpo = {sizeof(wpo),WPSTYLE_STRETCH};
    		_com_ptr_t<_com_IIID<IActiveDesktop,
    			&__uuidof(IActiveDesktop)> > lpIAD;
    
    		lpIAD.CreateInstance(CLSID_ActiveDesktop);	
    
    		lpIAD->SetWallpaper(_bstr_t(szFile),0);
    
    		lpIAD->SetWallpaperOptions(&wpo,0);
    
    		lpIAD->ApplyChanges(AD_APPLY_ALL);
    
    
    		MessageBox(0,"Wallpaper changed","",MB_OK);
    
    	}
    	catch(_com_error& e){
    		MessageBox(0,(e.Description().length() ? 
    			e.Description() : "COM Error"),0,MB_OK);
    	}
    
    	return 0;
    }
    The following are the errors I get when compiling (I have also added the preprocessor directive as described in the MSDN article.)

    main.cpp(29): error C2787: 'IActiveDesktop' : no GUID has been associated with this object
    main.cpp(29): error C3203: '_com_IIID' : class template invalid as template argument for template parameter '_IIID', expected a real type
    c:\Program Files\Microsoft Visual Studio .NET\Vc7\include\comip.h(62): error C2825: '_IIID::Interface': cannot form a qualified name
    c:\Program Files\Microsoft Visual Studio .NET\Vc7\include\comip.h(62): error C2039: 'Interface' : is not a member of 'operator``global namespace'''
    c:\Program Files\Microsoft Visual Studio .NET\Vc7\include\comip.h(62): fatal error C1507: previous user errors and subsequent error recovery halt further compilation
    Are there any specific project settings I need to implement here?
    Last edited by dalek; 04-14-2004 at 05:24 AM.

  4. #4
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    You need <shlguid.h>. If you can find where that is documented, you're doing better than me! I had the same problem a few days ago with IShellLink, but not using smart pointers, the problem was a little easier to diagnose. Also, you should have <objbase.h> above all other COM related headers.

  5. #5
    Registered User dalek's Avatar
    Join Date
    May 2003
    Posts
    135
    LOL - thanks. Your right, I can't find that documented anywhere!

    But the comedy is I still can't get this to work.

    Exactly the same errors as before. I think I have gone through every project setting available!

    #include <windows.h>
    #include <objbase.h>
    #include <wininet.h>
    #include <shlguid.h>
    #include <shlobj.h>
    #include <comdef.h>
    Changed the headers as above..

    Thanks heaps for the help BTW.

  6. #6
    Registered User dalek's Avatar
    Join Date
    May 2003
    Posts
    135
    Mmm.. I may have something here. I can get it to work if I am not using the smart pointers...

  7. #7
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    I don't think the & should be before the uuidof(). Also try:
    Code:
    		_com_ptr_t<_com_IIID<IActiveDesktop,
    			&IID_IActiveDesktop)> >
    Other than that, I'm out of ideas. You need someone who knows what they are talking about.

    EDIT: It seems to be already declared in <comdef.h> Try just:
    Code:
    IActiveDesktopPtr lpIAD;
    Last edited by anonytmouse; 04-14-2004 at 07:32 AM.

  8. #8
    Registered User dalek's Avatar
    Join Date
    May 2003
    Posts
    135
    Thanks mate. I think you have given me enough to work this out.

  9. #9
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    The __uuidof trick worked on the version of VC++ I was using...It can be handy on a few occasions

    try;

    _com_ptr_t<_com_IIID<IActiveDesktop, &IID_IActiveDesktop> > lpIAD;

  10. #10
    Registered User dalek's Avatar
    Join Date
    May 2003
    Posts
    135
    Yup - that works a treat!

  11. #11
    Registered User dalek's Avatar
    Join Date
    May 2003
    Posts
    135
    Damn it, from one problem to the next!

    Having worked this out in a procedural manner I am attempting to work this out in a OOP fashion.

    Unfortunately I keep getting an error 183: Cannot create a file when that file already exists.

    Now, I have a class that represents the active desktop.

    And just for the sake of testing I have put the following code in the constructor:
    Code:
    CWallpaper::CWallpaper()
    {
    	CoInitialize(0);
    
    	HRESULT hr;
    	IActiveDesktop *pActiveDesktop;
    
    	//Create an instance of the Active Desktop
    	hr = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER,
    						IID_IActiveDesktop, (void**)&pActiveDesktop);
    
    	WALLPAPEROPT opt;
    
    	opt.dwSize = sizeof(WALLPAPEROPT);
    	opt.dwStyle = 2;
    
    	//Insert code to call the IActiveDesktop methods
    	pActiveDesktop->SetWallpaper(L"c:\\tmp\\shores.bmp", 0);
    	pActiveDesktop->SetWallpaperOptions(&opt, 0);
    
    	pActiveDesktop->ApplyChanges(AD_APPLY_ALL);
    
    	// Call the Release method
    	pActiveDesktop->Release();
    }
    The error is occuring just after the call to CoCreateInstance. Any Ideas, google hasn't been to helpful in this respect..

    Cheers.

    EDIT: I may have it working, but I am not sure why, can anyone shed any light on what the error message actually means in this context (I have been able to attribute it to many errors, but none that are relevant to this problem)?
    Last edited by dalek; 04-15-2004 at 07:24 AM.

  12. #12
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    CoCreateInstance() and other com apis do not return an error via SetLastError()/GetLastError(). If the thread error number happens to be set after a call to a com function, it does not even mean that the function has failed. You should only rely on the return HRESULT.

    In fact this applies to non-com functions. You can only rely on the error number if it is documented that you can do so. (For most functions, but not all, this is only when the function returns failure).

    For example a function (eg. CoCreateInstance()) may call CreateFile():
    CreateFile documentation:
    If the function succeeds, the return value is an open handle to the specified file. If the specified file exists before the function call and dwCreationDisposition is CREATE_ALWAYS or OPEN_ALWAYS, a call to GetLastError returns ERROR_ALREADY_EXISTS (even though the function has succeeded). If the file does not exist before the call, GetLastError returns zero.
    So the error number can be set even though the outer function may have succeeded.

    Use the SUCCEEDED() and FAILED() macros to check hresults.

    P.S I take it you gave up on using smart pointers.
    Last edited by anonytmouse; 04-15-2004 at 09:04 AM.

  13. #13
    Registered User dalek's Avatar
    Join Date
    May 2003
    Posts
    135
    P.S I take it you gave up on using smart pointers.
    LOL - no. No the smart pointers work a treat, when I am proving code however I like to keep it as simple as possible.

    Thanks for the info though - I am somewhat new to the COM side of things and it is kind of doing my head in a bit.

    By the way, it just started working. I didn't change a thing and it just started working. Odd ay.

    You should only rely on the return HRESULT.
    Ahh.. well, the return HRESULT was also NULL so there was definitely a problem, but I think everything else I was doing was confusing the issue.

    Thanks again.

  14. #14
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    >> well, the return HRESULT was also NULL <<

    Code:
    hr == NULL == 0 == S_OK == NOERROR == Success!
    hr < 0 == Failure.
    hr > 0 == Success with status.

  15. #15
    Registered User dalek's Avatar
    Join Date
    May 2003
    Posts
    135
    Doh!

    [edit]
    Actually, just reexamined that project - I actually meant it did not return S_OK - so I am not the idiot that we all thought I was (almost).
    Last edited by dalek; 04-17-2004 at 09:04 PM.

Popular pages Recent additions subscribe to a feed