I am using the DataTransferManager in my Win32 Desktop Bridge App to share text and links.
I am using the samplecode from
Microsofts Code examples (github)
However the share dialog is empty (see image, its says "Try again, Could not show all available methods to share").
Loading DataTransferManagerHelper
IntPtr hwnd = new WindowInteropHelper(Application.Current.MainWindow).Handle;
var dtm = DataTransferManagerHelper.GetForWindow(hwnd);
dtm.DataRequested += OnDataRequested;
Showing Share UI
IntPtr hwnd = new WindowInteropHelper(Application.Current.MainWindow).Handle;
DataTransferManagerHelper.ShowShareUIForWindow(hwnd);
I was able to find the bug.
I was not actually calling the methods
DataTransferManagerHelper.GetForWindow(hwnd);
dtm.DataRequested += OnDataRequested;
Makes sure that these two methods get called otherwise you will get the "no content" share dialog.
Related
I'm currently creating a WPF application, and like to add as a small side feature the ability to clear the windows file explorer history.
If one were to manually do this operation, it is possible via the file menu within a file explorer window,
as shown here.
My goal is pretty much to programmatically execute the same action as this button does, but I've been unable to find what executable or user32.dll method is behind this operation (if it exists), and been also unsuccessful on finding the full logic behind it (namely, finding what folder and files it targets), to replicate it.
Can you help me?
As the comment by dxiv suggested, you can achieve this via the following:
enum ShellAddToRecentDocsFlags
{
Pidl = 0x001,
Path = 0x002,
PathW = 0x003
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern void SHAddToRecentDocs(ShellAddToRecentDocsFlags flag, string path);
// How To Clear Everything
SHAddToRecentDocs(ShellAddToRecentDocsFlags.Pidl, null);
I am trying to create an application in C# using which I need to change the BackColor/Forecolor of some specific controls in another process/application. For example I have few application running in my machine. When I run the new C# application (which does not have any UI), the backcolor/forecolor of few controls in other applications should be changed to the new colors which I set. And when I close the application, the colors should be reset to the original colors. I tried the SetTextColor, SetBkColor windows apis from gdi32 but they dont work. Could you suggest me how can I achieve this?
Note: The coordinates of the controls for which the colors need to be changed are already noted and I am using the WindowFromPoint api to get the handle of the control.
This is the code which I tried.
point = new Point(1340, 144);
IntPtr hWnd = DllImports.WindowFromPoint(point);//this is a button control in one of the applications
if (hWnd != IntPtr.Zero)
{
IntPtr wDC = DllImports.GetDC(hWnd);
int result = DllImports.SetBkMode(wDC, TRANSPARENT);
int i = DllImports.SetTextColor(wDC, ColorTranslator.ToWin32(Color.Red));
i = DllImports.SetBkColor(wDC, ColorTranslator.ToWin32(Color.Yellow));
result = DllImports.SetBkMode(wDC, OPAQUE);
}
Thanks in advance
Maybe I am just missing some silly link on the MSDN, but I cannot seem to find the list of possible values RegisterWindowMessage() can take
The only one I can find is "WM_HTML_GETOBJECT". I found this on pinvoke.net.
This however, I believe this crashes my application because what I am trying to get is an IHTMLDialog and not a IHTMLDocument
I have looked at
Message Reference
Message Constants
SendMessage
OCM_BASE
WM_USER
A google search for RegisterWIndowMessage list of possible values
Another google search for send message types
Maybe I am searching for the wrong things, but I sure can't find it.
My application fails here:
Dialog = (IHTMLDialog)ObjectFromLresult(lRes, typeof(IHTMLDialog).GUID, IntPtr.Zero);
However I believe the issue happened further up the pipeline up here :
uint iMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
Because this is not an HTML document, but actually a dialog.
If it helps I am getting the hwnd to the dialog this way :
IntPtr hwnd = FindWindow("Internet Explorer_TridentDlgFrame", "Google -- Webpage Dialog");
Here is the full snippet of what I am trying to do if it helps :
UIntPtr lRes;
IHTMLDialog Dialog;
IntPtr hwnd = FindWindow("Internet Explorer_TridentDlgFrame", "Google -- Webpage Dialog");
uint iMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
if (SendMessageTimeout(hwnd, iMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes) == IntPtr.Zero)
{
MessageBox.Show("operation failed");
}
else
{
Dialog = (IHTMLDialog)ObjectFromLresult(lRes, typeof(IHTMLDialog).GUID, IntPtr.Zero);
}
RegisterWindowMessage takes a string argument. You can pass any string value. If you are registering messages for your application, make sure to use unique string values (e.g. string representations of GUIDs).
Other than that, there is no complete list of string values you can pass, because any application can choose to register its own set of messages. You will have to consult the documentation that comes with those applications to find out, which messages it supports (if any).
I am working from the sample project here: http://www.codeproject.com/Articles/8086/Extending-the-save-file-dialog-class-in-NET
I have hidden the address/location bar at the top and made other modifications but I can't for the life of me manage to disable the button that lets you go up to the parent folder. Ist is in the ToolbarWindow32 class which is the problem. This is what I have at the moment but it is not working:
int parentFolderWindow = GetDlgItem(parent, 0x440);
//Doesn't work
//ShowWindow((IntPtr)parentFolderWindow, SW_HIDE);
//40961 gathered from Spy++ watching messages when clicking on the control
// doesn't work
//SendMessage(parentFolderWindow, TB_ENABLEBUTTON, 40961, 0);
// doesn't work
//SendMessage(parentFolderWindow, TB_SETSTATE, 40961, 0);
//Comes back as '{static}', am I working with the wrong control maybe?
GetClassName((IntPtr)parentFolderWindow, lpClassName, (int)nLength);
Alternatively, if they do use the parent folder button and go where I don't want them to, I'm able to look at the new directory they land in, is there a way I can force the navigation to go back?
Edit: Added screenshot
//Comes back as '{static}', am I working with the wrong control maybe?
You know you are using the wrong control, you expected to see "ToolbarWindow32" back. A very significant problem, a common one for Codeproject.com code, is that this code cannot work anymore as posted. Windows has changed too much since 2004. Vista was the first version since then that added a completely new set of shell dialogs, they are based on IFileDialog. Much improved over its predecessor, in particular customizing the dialog is a lot cleaner through the IFileDialogCustomize interface. Not actually what you want to do, and customizations do not include tinkering with the navigation bar.
The IFileDialogEvents interface delivers events, the one you are looking for is the OnFolderChanging event. Designed to stop the user from navigating away from the current folder, the thing you really want to do.
While this looks good on paper, I should caution you about actually trying to use these interfaces. A common problem with anything related to the Windows shell is that they only made it easy to use from C++. The COM interfaces are the "unfriendly" kind, interfaces based on IUnknown without a type library you can use the easily add a reference to your C# or VB.NET project. Microsoft published the "Vista bridge" to make these interfaces usable from C# as well, it looks like this. Yes, yuck. Double yuck when you discover you have to do this twice, this only works on later Windows versions and there's a strong hint that you are trying to do this on XP (judging from the control ID you found).
This is simply not something you want to have to support. Since the alternative is so simple, use the supported .NET FileOk event instead. A Winforms example:
private void SaveButton_Click(object sender, EventArgs e) {
string requiredDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
using (var dlg = new SaveFileDialog()) {
dlg.InitialDirectory = requiredDir;
dlg.FileOk += (s, cea) => {
string selectedDir = System.IO.Path.GetDirectoryName(dlg.FileName);
if (string.Compare(requiredDir, selectedDir, StringComparison.OrdinalIgnoreCase) != 0) {
string msg = string.Format("Sorry, you cannot save to this directory.\r\nPlease select '{0}' instead", requiredDir);
MessageBox.Show(msg, "Invalid folder selection");
cea.Cancel = true;
}
};
if (dlg.ShowDialog() == DialogResult.OK) {
// etc...
}
}
}
I don't this is going to work. Even if you disable the button they can type ..\ and click save and it will take them up one level. You can't exactly disable the file name text box and maintain the functionality of the dialog.
You'd be better off either using the FolderBrowserDialog and setting it's RootFolder property and asking the user to type the filename in or auto generating it.
If the folder you are wanting to restrict the users to isn't an Environment.SpecialFolder Then you'll need to do some work to make the call to SHBrowseForFolder Manually using ILCreateFromPath to get a PIDLIST_ABSOLUTE for your path to pass to the BROWSEINFO.pidlRoot
You can reflect FolderBrowserDialog.RunDialog to see how to make that call.
Since you want such custom behaviors instead of developing low level code (that is likely yo break in the next versions of windows) you can try to develop your file picker form.
Basically it is a simple treeview + list view. Microsoft has a walk-through .
It will take you half a day but once you have your custom form you can define all behaviors you need without tricks and limits.
I have seen numerous posts on this subject here, but none seem to answer this issue directly. I want to control two instances of Powerpoint running on a second monitor.
The ideal solution looks like this:
PowerPoint.Application PPTViewer1 = new PowerPoint.Application();
PowerPoint.Application PPTViewer2 = new PowerPoint.Application();
I can do this manually, simply by starting two instances of PowerPoint, loading the presentation, and starting the slide show from each instance. I can toggle back and forth between the two slide shows manually, with each being brought to the front as expected.
So... how do I do this programatically using VSTO and C#?? Like others before me, I see that the Interop.PowerPoint interface will create only the single instance. If that were not the case, then I could achieve the results I am looking for easily enough.
Additionally, I am not looking for a third party component for this task.
Any help is appreciated.
Thanks in advance.
It may appear that you're running multiple instances of Powerpoint, but you're not. It only allows one instance of itself. If you see two instances of Powerpnt.exe in the task list, as sometimes happens, it means that something's gone wrong and left a zombie in memory.
May not be totally ideal but here is a reference that suggested to start an instance as a different user (Note that this site is for PowerPoint 2007).
runas /user:username "C:\Program Files\Microsoft Office\Office12\POWER PNT.EXE"
Each instance of the Powerpoint COM object shares the same fullscreen display window. I know of no method to switch which presentation has that window
The solution is to host the Powerpoint display in your own window
This therefore allows you to scale the window and show multiple presentations on one monitor, or move it from one monitor to another?
e.g.
var display1 = new FullScreenDisplay(); // A form with BorderStyle = None
display1.Show();
application1 = new PowerPoint.Application();
presentation1 = application1.Presentations.Open2007(....);
var slideShowSettings1 = presentation1.SlideShowSettings;
slideShowSettings1.ShowType = PowerPoint.PpSlideShowType.ppShowTypeSpeaker;
var slideShowWindow1 = slideShowSettings1.Run();
IntPtr hwnd1 = (IntPtr)slideShowWindow1.HWND;
SetParent(hwnd1, display1.Handle);
var display2 = new FullScreenDisplay();
display2.Show();
application2 = new PowerPoint.Application();
presentation2 = application2.Presentations.Open2007(....);
var slideShowSettings2 = presentation2.SlideShowSettings;
slideShowSettings2.ShowType = PowerPoint.PpSlideShowType.ppShowTypeSpeaker;
var slideShowWindow2 = slideShowSettings2.Run();
IntPtr hwnd2 = (IntPtr)slideShowWindow2.HWND;
SetParent(hwnd2, display2.Handle);
display1.BringToFront(); // to show slideshow 1
// or
display2.BringToFront(); // to show slideshow 2
// To advance a slide
presentation1.SlideShowWindow.View.Next();
// or
presentation2.SlideShowWindow.View.Next();
// To exit, note order!
presentation2.SlideShowWindow.View.Exit();
presentation1.SlideShowWindow.View.Exit();
Application.Exit();
This is a hack, and may not work in future versions of Powerpoint?
You also need this import
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);