How can I get a URL entered into WinForms OpenFileDialog? - c#

If a user enters a URL into a Windows Forms OpenFileDialog then the dialog box (on more modern versions) of Windows will download the file and open it from a temporary directory. Is there any way to get at the entered URL? Could the new-fangled IFileDialog help?
Please note that I am not looking for the file:// equivalent of a local file. This is for when the user enters the location of something on the Internet into the file dialog. e.g. http://example.com/path.
This asks essentially the same question, but didn't get a useful answer, perhaps because he asks that the result appear in the FileName property.

It's possible to set a windows hook to listen for text changes. This code currently picks up value changes from all fields, so you will need to figure out how to only detect the ComboBox filename field.
public class MyForm3 : Form {
public MyForm3() {
Button btn = new Button { Text = "Button" };
Controls.Add(btn);
btn.Click += btn_Click;
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventProc lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
private static extern bool UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
private const int WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_OBJECT_VALUECHANGE = 0x800E;
void btn_Click(object sender, EventArgs e) {
uint pid = 0;
uint tid = 0;
using (var p = Process.GetCurrentProcess())
GetWindowThreadProcessId(p.MainWindowHandle, out pid);
var hHook = SetWinEventHook(EVENT_OBJECT_VALUECHANGE, EVENT_OBJECT_VALUECHANGE, IntPtr.Zero, CallWinEventProc, pid, tid, WINEVENT_OUTOFCONTEXT);
OpenFileDialog d = new OpenFileDialog();
d.ShowDialog();
d.Dispose();
UnhookWinEvent(hHook);
MessageBox.Show("Original filename: " + OpenFilenameText);
}
private static String OpenFilenameText = "";
private static WinEventProc CallWinEventProc = new WinEventProc(EventCallback);
private delegate void WinEventProc(IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime);
private static void EventCallback(IntPtr hWinEventHook, int iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime) {
StringBuilder sb1 = new StringBuilder(256);
GetClassName(hWnd, sb1, sb1.Capacity);
if (sb1.ToString() == "Edit") {
StringBuilder sb = new StringBuilder(512);
GetWindowText(hWnd, sb, sb.Capacity);
OpenFilenameText = sb.ToString();
}
}
}

If you only want to get URL (not download file), set CheckFileExists flag to false.
Example code below
string urlName = null;
using (var dlg = new OpenFileDialog())
{
dlg.CheckFileExists = false;
dlg.ShowDialog();
urlName = dlg.FileName;
urlName = Path.GetFileName(urlName);
}

Related

Using SendMessage() to write to Excel in C#

I made before a program where I could open a process of the notepad and while it's opened, be able to write in it from the C# program console. Now I'm trying to do the same but with the excel, I can run the process, I can open it and I can kill it. But when I try to write in it with the SendMessage() method, nothing happens, is there a way I can do this? Or am I missing something? Thanks!
Here's what I tried so far
Declarations
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
//include SendMessage
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, int lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
[DllImport("User32.dll")]
static extern int SetForegroundWindow(IntPtr point);
[DllImport("User32.dll", EntryPoint = "SendMessage")]
extern static int SendMessageGetTextLength(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
const uint WM_PASTE = 0x302;
const int WM_SETTEXT = 0X000C;
const int WM_GETTEXTLENGTH = 0x000E;
const int EM_SETSEL = 0x00B1;
const int EM_REPLACESEL = 0x00C2;
static void Main(string[] args)
{
//Abre o programa
Process prcss = new Process();
prcss.StartInfo.FileName = "excel.exe";
prcss.Start();
string aux = prcss.StartInfo.FileName;
//Verifica se o processo está a correr
Process[] processlist = Process.GetProcesses();
Code to write in it with the SendMessage().
case "2":
while (true)
{
//Testar com o SendMessage
Console.WriteLine("\nTexto: \n");
string texto = Console.ReadLine();
if (aux.Length == 0)
{
return;
}
if (prcss != null)
{
IntPtr notepadTextbox = FindWindowEx(prcss.MainWindowHandle, IntPtr.Zero, "edit", null);
int length = SendMessageGetTextLength(notepadTextbox, WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
if (!notepadTextbox.Equals(IntPtr.Zero))
{
//sending the message to the textbox
SendMessage(notepadTextbox, WM_SETTEXT, 0, texto);
SendMessage(notepadTextbox, EM_SETSEL, length, length);
SendMessage(notepadTextbox, EM_REPLACESEL, 1, texto + "\n");
}
}
Console.WriteLine("Sair? (S)im / (N)ão");
sair = Console.ReadLine();
if (sair == "s" || sair == "S")
{
IntPtr k = prcss.MainWindowHandle;
SetForegroundWindow(k);
prcss.Kill();
break;
}
}

C# - WINAPI CB_SETCURSEL not working as expected

So I am trying to update a combobox in another application programmatically. The application I am updating has a combobox, some textboxes, and a number of checkboxes. Depending on the item selected in the combobox certain checkboxes will become enabled or disabled. The problem I am having is that, although I can change the current item in the combobox, the gui doesn't seem to be updated the checkboxes accordingly.
Here is my code
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
const int CB_SETCURSEL = 0x014E;
static void Main(string[] args)
{
var startinfo = new ProcessStartInfo("path");
// Get an object that contains all the process resources
Process rtugen = Process.Start(startinfo);
// wait until the process has a main window handle
while (rtugen.MainWindowHandle == IntPtr.Zero)
{
rtugen.Refresh();
}
IntPtr hWnd = rtugen.MainWindowHandle;
IntPtr controllerType = FindWindowEx(hWnd, IntPtr.Zero, "ComboBox", null);
SendMessage(controllerType, CB_SETCURSEL, 12, "");
int send_cbn_selchange = MakeWParam((int)controllerType, CBN_SELCHANGE);
int i = SendMessage(hWnd, 0x111, send_cbn_selchange,0);
}
static int MakeWParam(int loWord, int hiWord)
{
return (loWord & 0xFFFF) + ((hiWord & 0xFFFF) << 16);
}
So, the above code does update the combobox, but the GUI doesn't seem to update the checkboxes after the update is made. I monitored the combobox change in spy++ and it showed me the same command being sent. Any ideas on what is going wrong?
Eventually I found this solution online to change the value of the combobox so that the application recognizes the change. Once you have a handle on the combobox you can use the WM_KEYDOWN msg to simulate key down action.
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
const int CB_SETCURSEL = 0x014E;
const int VK_DOWN = 0x28;
const int WM_KEYDOWN = 0x0100;
static void Main(string[] args)
{
var startinfo = new ProcessStartInfo("path");
// Get an object that contains all the process resources
Process rtugen = Process.Start(startinfo);
// wait until the process has a main window handle
while (rtugen.MainWindowHandle == IntPtr.Zero)
{
rtugen.Refresh();
}
IntPtr hWnd = rtugen.MainWindowHandle;
IntPtr controllerType = FindWindowEx(hWnd, IntPtr.Zero, "ComboBox", null);
SendMessage(controllerType, CB_SETCURSEL, 0, "");
for (int i = 0; i < Index; i++)
SendMessage(controllerType, WM_KEYDOWN, VK_DOWN, 0);
}

Trying to read the active window title when it changes in Console Application

I am trying to make a program that writes the active window title, whenever it changes to the console window.
Here's my code, It does work in a winform application but not in a console application, I couldn't figure out what's wrong.
Any help would be appreciated.
class Program
{
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
private const uint WINEVENT_OUTOFCONTEXT = 0;
private const uint EVENT_SYSTEM_FOREGROUND = 3;
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
private string GetActiveWindowTitle()
{
const int nChars = 256;
IntPtr handle = IntPtr.Zero;
StringBuilder Buff = new StringBuilder(nChars);
handle = GetForegroundWindow();
if (GetWindowText(handle, Buff, nChars) > 0)
{
return Buff.ToString();
}
return null;
}
public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
Console.WriteLine(GetActiveWindowTitle() + "\r\n");
}
static void Main(string[] args)
{
WinEventDelegate dele = null;
Program a = new Program();
dele = new WinEventDelegate(a.WinEventProc);
IntPtr m_hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, dele, 0, 0, WINEVENT_OUTOFCONTEXT);
Console.ReadKey();
}
}
"The client thread that calls SetWinEventHook must have a message loop in order to receive events." Threads in a console application don't have message loops. Unless you build one:
using System.ComponentModel;
using System.Windows.Forms;
...
[DllImport("user32.dll", SetLastError = true)]
static extern int GetMessage(out Message lpMsg, IntPtr hwnd, int wMsgFilterMin, int wMsgFilterMax);
[DllImport("user32.dll")]
static extern int TranslateMessage(Message lpMsg);
[DllImport("user32.dll")]
static extern int DispatchMessage(Message lpMsg);
Then replace Console.ReadKey() with
Message msg;
while (true) {
int result = GetMessage(out msg, IntPtr.Zero, 0, 0);
if (result == 0) break;
if (result == -1) throw new Win32Exception();
TranslateMessage(msg);
DispatchMessage(msg);
}
I'm being lazy and taking the Message structure from System.Windows.Forms. You could add the definition of that separately if you don't want to take the dependency.
Since this thread is now occupied with processing messages, you probably want to do this on a separate dedicated thread if you want to do other processing.

Hosting a process in C#.Net form disables some process's buttons

I am trying to host a .exe within my .net application (Mainly video viewing software) however certain applications do not allow me to use their menu's or some controls. Has anyone had this problem before or any idea of why it could be happening?
Here is my code to host the application:
#region Methods/Consts for Embedding a Window
[DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true,
CharSet = CharSet.Unicode, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
private static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
private static extern long GetWindowLong(IntPtr hwnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport("user32.dll", SetLastError = true)]
private static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
[DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
private static extern bool PostMessage(IntPtr hwnd, uint Msg, int wParam, int lParam);
private const int SWP_NOOWNERZORDER = 0x200;
private const int SWP_NOREDRAW = 0x8;
private const int SWP_NOZORDER = 0x4;
private const int SWP_SHOWWINDOW = 0x0040;
private const int WS_EX_MDICHILD = 0x40;
private const int SWP_FRAMECHANGED = 0x20;
private const int SWP_NOACTIVATE = 0x10;
private const int SWP_ASYNCWINDOWPOS = 0x4000;
private const int SWP_NOMOVE = 0x2;
private const int SWP_NOSIZE = 0x1;
private const int GWL_STYLE = (-16);
private const int WS_VISIBLE = 0x10000000;
private const int WM_CLOSE = 0x10;
private const int WS_CHILD = 0x40000000;
private const int WS_MAXIMIZE = 0x01000000;
#endregion
#region Variables
private IntPtr hostedProcessHandle;
private Process hostedProcess = null;
private ProcessStartInfo hostedPSI = new ProcessStartInfo();
#endregion
//Helper method to start a process contained within the form
private void HostProcess(string processPath)
{
//Start the process located at processPath
hostedPSI.FileName = processPath;
hostedPSI.Arguments = "";
hostedPSI.WindowStyle = ProcessWindowStyle.Maximized;
hostedProcess = System.Diagnostics.Process.Start(hostedPSI);
//Stop watch is used to calculate time out period.
Stopwatch sw = new Stopwatch();
sw.Start();
//Loop to aquire application handle. Exit loop if the time out period is past.
do
{
hostedProcessHandle = hostedProcess.MainWindowHandle;
if (sw.ElapsedMilliseconds > 10000) throw new TimeoutException();
} while (hostedProcessHandle == new IntPtr(0));
//Host the process in the forms panel.
SetParent(hostedProcessHandle, this.panel1.Handle);
SetWindowLong(hostedProcessHandle, GWL_STYLE, WS_VISIBLE + WS_MAXIMIZE);
MoveWindow(hostedProcessHandle, 10, 10, this.panel1.Width - 20, this.panel1.Height - 20, true);
}
private void CloseHostedProcess()
{
hostedProcess.Kill();
}
Here is a screen shot of my test application hosting VLC, Some of the menu's and buttons as you can see are grayed out and not working:
This is not just a problem with VLC — I see this issue when hosting other applications too.
Just an update. If i right click on VLC -> Play -> Add and play a video back manually the menu bar works again. However the video controls at the bottom are still not working! They change color when rolled over but clicking them still doesn't work!
The reason I was experiencing problems seems to be because TeamViewer was running in the background. I am currently trying to find out why this causes me issues but stopping TeamViewer's process seems to rectify my problem.

How to programmatically install a font

I would like to install a specific font on my program load and use that font in rendering text of the program. How can I programmatically install a font from .NET CF on WinCE 6.
This blog entry shows how to enumerate and add Fonts in Windows CE using native code. For managed code, this will work:
internal class FontHelper
{
private delegate int EnumFontFamProc(IntPtr lpelf, IntPtr lpntm, uint FontType, IntPtr lParam);
private List<string> m_fonts = new List<string>();
public FontHelper()
{
RefreshFontList();
}
public void RefreshFontList()
{
m_fonts.Clear();
var dc = GetDC(IntPtr.Zero);
var d = new EnumFontFamProc(EnumFontCallback);
var ptr = Marshal.GetFunctionPointerForDelegate(d);
EnumFontFamilies(dc, null, ptr, IntPtr.Zero);
}
public string[] SupportedFonts
{
get { return m_fonts.ToArray(); }
}
private const int SIZEOF_LOGFONT = 92;
private const int LOGFONT = 28;
private const int LF_FACESIZE = 32;
private const int LF_FULLFACESIZE = 64;
[DllImport("coredll", SetLastError = true)]
private static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("coredll", SetLastError = true)]
private static extern int EnumFontFamilies(IntPtr hdc, string lpszFamily, IntPtr lpEnumFontFamProc, IntPtr lParam);
private int EnumFontCallback(IntPtr lpelf, IntPtr lpntm, uint FontType, IntPtr lParam)
{
var data = new byte[SIZEOF_LOGFONT + LF_FACESIZE + LF_FULLFACESIZE];
Marshal.Copy(lpelf, data, 0, data.Length);
var fontName = Encoding.Unicode.GetString(data, SIZEOF_LOGFONT, LF_FULLFACESIZE).TrimEnd('\0');
Debug.WriteLine(fontName);
m_fonts.Add(fontName);
return 1;
}
}
Copy font *.ttf file to Windows\Fonts folder, it may requires restarting your device.
Actually, this helps better.
http://social.msdn.microsoft.com/Forums/en/netfxcompact/thread/ee9a6947-0799-4a76-a7cd-c0bec4b7a2ab

Categories

Resources