Ole drag & drop troubleshooting - c++

I have created a Dialog using WTL, inheriting from CDialogImpl class, inside the main dialog I have created another dialog and inside this second child dialog a list control. I wanted to add drag& drop functionality to the list control, I have read on the web about the WM_DROPFILES method and about the Ole Drop Target, I have chosen the later one.
I have implemented the IDropTarget interface methods in accordance to this.
I have set the accept files option to TRUE in all my dialogues, I have instantiated the IDropTarget in the child dialogue class and called the following methods in its WM_INITDIALOGUE handler:
//drag& drop
lpDropTarget = (LPDROPTARGET)new TDropTarget(m_hWnd);
CoLockObjectExternal(lpDropTarget, true, true);
// register the HWND as a drop target
RegisterDragDrop(m_hWnd, lpDropTarget);
lpDropTarget is instantiated as follows:
LPDROPTARGET lpDropTarget;
And that's about it. Haven't really used Ole before so I have tried the following scenarios in search of luck:
I have registered with RegisterDragDrop for the List control HWND and set it's parent dialogue to receive the notification WM_OLEDROP WM_USER + 1 that I send. Ok the cursor for drag & drop showed but no calls to the implementation of the functions of IDataTarget.
RegisterDragDrop for child dialogue & notifications for it also.
RegisterDragDrop for the main Dialog & notifications for it also.
In the later cases ( 2 & 3) the cursor for drag& drop didn't even appeared, it showed me the no-drag & drop allowed one.
Now, all the dialogues and list control have been set to accept files from the visual studio designer.
I am limited to using only ATL /WTL/WINAPI, no MFC.
What am I doing wrong?

For you WM_DROPFILES is the only thing you need to handle. No need to fiddle with IDropTarget etc.
If your application does not need to run in Admin mode, do not run it in admin mode. Disable the linker setting for the same (UAC Execution Level = asInvoker). Also, run VS in non-Admin mode, so that your application also starts are non-Admin process. This way, Explorer.exe would be able to send WM_DROPFILES message to your application.
If your application need to run as Admin mode, you need to allow other applications to send set of few messages to your application (window). Do the following:
ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD);
ChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD);
ChangeWindowMessageFilter(0x0049, MSGFLT_ADD);
You may also want to use newer function: ChangeWindowMessageFilterEx.
Note that, if your application must run as Admin, and you need to dynamically locate one of these function using GetProcAddress, so that your application can run on OS where this function is not available (eg. Windows XP).

Related

Display and use the same MFC CList control in multiple dialogs

I am coding a test application for a windows CE device. This is the first time I am programming for a handheld device. I use MFC VC++ on Visual Studio 2008. I have found that there are many restrictions in the controls and what I could do with them when running the program on a handy versus when I run a similar program on a desktop computer.
Now, the device I am currently deploying my test program to, does not have a touchscreen and has few extra keys other that the numberpad 0-9 keys. So, I have to do with a simple GUI that uses keydowns to call specific functions like add, edit, delete etc... It also forces me to use separate dialogs for each of these functions so as to avoid unnecessary mouse cursor usage.
This leads me to my current problem: The 'ADD' dialog of my test app adds some user data to a CListCtrl that is on the 'MAIN' dialog. The 'EDIT/DELETE' dialog is to allow the user to select the desired data from its own CListCtrl and press the "ENTER" key, which thereby deletes the selected data from the 'MAIN' dialog's CListCtrl. Thus, both the main dialog and the 'EDIT/DELETE' dialog have CListCtrl with the exact same data. So, instead of having to use 2 separate list controls and using loops to copy the data to and fro among them, is there a way in which i could use the exact same CListCtrl (one and only one instance of the CListCtrl exists), but display it on 2 separate dialogs? This would remove all the copying code, as well as halve the amount of data in memory.
I tried passing a pointer to the MAIN dialog's CListCtrl to the 'EDIT/DELETE' dialog in hopes that I could redraw the control there, but in vain. I could call the RedrawWindow, RedrawItems commands, but they seem to have no effect in the 'EDIT/DELETE' dialog (I think it is because the control itself is not present on the edit/delete dialog). Any other suggestions?
You could temporarily change the parent of the ListCtrl using CWnd::SetParent to the EDIT/DELETE dialog, and set the position with CWnd::SetWindowPos to where you want to have it. When the dialog gets closed, set the parent back to the MAIN dialog.

C++ Win32 get activated MDI szTitle

I'm writing a notepad program in MS C++ 2010 Express with Win32. So far whenever the user opens or saves the document, it updates the status bar with the saved / opened filename. I also want to change the status bar to the current filename everytime a different MDI is activated. How would I do this?
Your MDI child windows will get WM_MDIACTIVATE messages whenever their activation state changes - you then just have to pass that notification back to your top-level window in some way (via a custom message probably - you could even send the filename at the same time) to get it to update the status bar.
By the way, the MDI concept is more or less deprecated and Microsoft advise against using it in new applications:
Many new and intermediate users find it difficult to learn to use MDI
applications. Therefore, you should consider other models for your
user interface. However, you can use MDI for applications which do not
easily fit into an existing model
For a notepad-type application the "modern" way to do this would be via a tabbed interface.
This is what you need.
Send WM_MDIGETACTIVE to the current client to ge the active client.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644915%28v=vs.85%29.aspx

How to unload ActiveX's ocx without terminating main application to allow the ocx to be overwritten?

I have ActiveX controls implemented in VB6 and are instantiated inside MFC42 application.
I have a tree view structure on the left panel of the application and when different items in the tree are selected, different ActiveX are loaded accordingly on the right panel to display the details of the selected item.
Whenever I want to modify the VB code for the ActiveX, I will need to restart the application. This greatly interrupts the development flow since the application starts pretty slowly.
In some ActiveX we have dummy code/data to allow the ActiveX to be executed inside Internet Explorer, which is faster to load, but not all of our ActiveX have it.
I am expecting that when I click different item in the tree view, the previous ActiveX is unloaded and I can overwrite it with a new version.
If the ActiveX has never been instantiated/displayed, I am able to replace the ocx while the application is still running.
I searched in the internet and found two articles on ActiveX, both of them suggest that the proper way to clean up is to:
m_pControl = new CWnd;
m_pControl->CreateControl(strControlProgid,
"",
WS_VISIBLE,
rc,
this,
5000,
NULL,
FALSE,
NULL);
// ...
m_pControl->DestroyWindow();
delete m_pControl;
The ActiveXs we have are already destroyed using this method but I still need to exit the application in order to overwrite the ocx.
EDIT:
Alternatively, for VC++ 6 (with MFC42), instead of CoFreeUnusedLibrariesEx which is mentioned by Noseratio in his answer; I can use CoFreeUnusedLibraries which will work without delay for Single Threaded Apartement (STA).
Provided the COM reference counting works correctly in your app, you could try forcing to unload the no-longer-in-use ActiveX DLL with CoFreeUnusedLibrariesEx.

Adding accelerators(shortcuts) in MFC - HOW?

I found this link: http://support.microsoft.com/kb/222829
But I can't understand that much.
Ok, I understood I need to add this to my header file:
HACCEL m_hAccelTable;
and then this:
m_hAccelTable = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR1));
to my main .cpp
But where does this go?
BOOL CAboutDlg::PreTranslateMessage(MSG* pMsg) {
if (m_hAccelTable) {
if (::TranslateAccelerator(m_hWnd, m_hAccelTable, pMsg)) {
return(TRUE);
}
}
return CDialog::PreTranslateMessage(pMsg);
}
I need around 6 shortcuts (CTRL + U to load something, CTRL + O to load smth else), I can't understand how this works, need a little bit of help
Now, MSDN article is misleading. It shows how to add accelerators to About box and only About box will be able to handle accelerator that is in this case equivalent of pressing the button with IDC_BUTTON1 ID.
You need to do something very different allowing all objects in your application to get a chance to handle this message. This is done for you in MDI/SDI apps.
Once you create accelerator table in the resource, you have to add accelerators: Key combination paired Accelerator key combination, when used generates command message with appropriate ID. Once you are done adding, you have to create command message handlers for each of the ID.
When accelerator is used the handler is invoked and you can add the code you need.
Now do this:
Declare HACCEL type variable to your app class. In the InitInstance call LoadAccelerators.
Use wizard to insert PreTranslateMessage override in your application class. Add following:
if (m_hAccelTable)
{
if (::TranslateAccelerator(*m_pMainWnd, m_hAccelTable, pMsg))
{
return(TRUE);
}
}
This will allow the main dialog to handle accelerators. Note *m_pMainWnd. It is your dialog handle (automatically casted).
Now you can add handlers for any accelerator to the dialog or to the application class. You can also route command messages to any window in your application using OnCmdMsg.
My advice for the future.
When you decide to make your app a dialog based, consider creating SDI application with CFormView derived class.
You can change frame style to not allow resizing and it will look like dialog based but. . .
You will have ability to use a toolbar a menu for free and most importantly you will have all accelerator and command routing for free.
The page you referenced describes adding an accelerator table to a dialog based applicaion.
Are you creating a dialog based application or just a normal MFC frame based application with a menu bar?
If you are doing the former then as the page you referenced suggest you need to override the PreTranslateMessage dialog box method.
If you are doing the later then you only need to call the CFrameWnd::LoadAccelTable function.

can I set the AppUserModelID of an arbitrary process launched through a jumplist?

I have a simple console application written in C++ that acts as a stub for launching another application through it's jumplist. Purpose is to add jumplist abilities to applications that do not support this. Call it stub.exe. When running stub.exe it creates a custom jumplist using these steps (taken right form the MS samples):
create an ICustomDestinationList
ICustomDestinationList::BeginList()
create an IObjectCollection
for_each item_to_add
create an IShellLink, set its path/arguments/title/icon
add IShellLink to the IObjectCollection
get the IObjectArray interface from the IObjectCollection
call ICustomDestinationList::AddUserTasks( IObjectArray interface )
ICustomDestinationList::CommitList()
When pinning stub.exe to the taskbar and right-clicking it, the jumpilst appears and it contains all IShellLinks added. When clicking an item, it will launch the corresponding process.
Now I'd like a process launched through this jumplist have it's window(s) grouped under stub.exe's taskbar icon, instead of having it's own group. They key to get this working seems to be the AppUsermodelID. This is what I tried so far:
just for testing, create a couple of shortcuts and set the id through IPropertyStore->SetValue( PKEY_AppUserModel_ID, "id" ). Indeed, when launching these shortcuts, they will all group under the same taskbar icon.
since the shortcuts do what I want, I tried adding shortcuts to stub.exe's jumplist: no effect. The shortcuts don't even show up in the jumplist (maybe one cannot have a shortcut to a shortcut?), yet all methods return S_OK
setting the PKEY_AppUserModel_ID on each of the IShellLinks that get added to the jumplist: no effect
calling ICustomDestinationList->SetAppID(): no effect
instead of using SubTasks, tried with SHAddToRecentDocs: no effect. The recent doc list does not show up. But now things get messy. After setting the AppUserModelID on the shortcut that is responsible for the pinned taskbar item (the one in %APPDATA%/Roaming/Microsoft/Internet Explorer/Quick Launch/User Pinned/TaskBar), the jumplist changed: it does not show the 'Tasks' item anymore, but does show 'Recent' and the items I added using SHAddToRecentDocs. Now when clicking them I get a dialog box with a title that starts with 'd:\desktop' followed by Chinese characters. Hovering the items in the jumplist also shows Chinese characters instead of the descirption I set.
Questions:
What's with the Chinese characters in the jumplist?
How come setting the app id on the taskbar shortcut toggles between 'Tasks' and 'Recent' sections, why are they not both there?
What would be the way, if even possible, to achive what I actually want: a custom jump list of which the items launched will group under it's taskbar icon? (note that the processes I plan to laucnh their do not have their app id set currently)
not much reactions here ;]
In the meantime I managed to solve the main problem myself; it's not quite a straightforward solution but it fullfills the requirements: a program runs in the backround and installs a CBT hook. Each time an application creates a window (HookProc code = HCBT_CREATEWND), the hook checks the application's path against a map containing paths and desired application ids. If a match is found, the application id of the HWND is set. Since this occurs before the window is actually shown and is combined with the custom task list, from a user's point of view the application behaves just like one that does support a recent/pinned document list.