c# Customized file dialog to add additional control depending on selection - c#

I would like to customize a window 10 style file dialog (open) adding additional control below the file name filed (see the attached image). And update the additional control depending on the selection if I can.
Click here to see image
How I could do it?
- Add my additional controls on the dialog
- Hook callback
I try to hook the file dialog like below code, however, it seems that the classic dialog is only available.
Please help me to figure out this.
public struct OpenFileName
{
public Int32 lStructSize;
public IntPtr hwndOwner;
public IntPtr hInstance;
public IntPtr lpstrFilter;
public IntPtr lpstrCustomFilter;
...
public OfnHookProc lpfnHook;
...
};
[return: MarshalAs(UnmanagedType.SysUInt)]
public delegate IntPtr OfnHookProc(IntPtr hdlg, [MarshalAs(UnmanagedType.U4)] int uiMsg, IntPtr wParam, IntPtr lParam);
public CustomizedDialog(string defaultExtension, string directoryName)
{
// Need two buffers in unmanaged memory to hold the filename
// Note: the multiplication by 2 is to allow for Unicode (16-bit) characters
_fileNameBuffer = Marshal.AllocCoTaskMem(2 * _MAX_PATH);
_fileTitleBuffer = Marshal.AllocCoTaskMem(2 * _MAX_PATH);
_directoryBuffer = Marshal.AllocCoTaskMem(2 * _MAX_PATH);
// Zero these two buffers
byte[] zeroBuffer = new byte[2 * (_MAX_PATH + 1)];
for (int i = 0; i < 2 * (_MAX_PATH + 1); i++) zeroBuffer[i] = 0;
Marshal.Copy(zeroBuffer, 0, _fileNameBuffer, 2 * _MAX_PATH);
Marshal.Copy(zeroBuffer, 0, _fileTitleBuffer, 2 * _MAX_PATH);
Marshal.Copy(zeroBuffer, 0, _directoryBuffer, 2 * _MAX_PATH);
// copy initial directory name into unmanaged memory buffer
byte[] directoryBytes = Encoding.Unicode.GetBytes(directoryName);
Marshal.Copy(directoryBytes, 0, _directoryBuffer, directoryBytes.Length);
// Populate the OPENFILENAME structure
// The flags specified are the minimal set to get the appearance and behaviour we need
_ofn.lStructSize = Marshal.SizeOf(_ofn);
_ofn.lpstrFile = _fileNameBuffer;
_ofn.nMaxFile = _MAX_PATH + 1;
_ofn.lpstrDefExt = Marshal.StringToCoTaskMemUni(defaultExtension);
_ofn.lpstrFileTitle = _fileTitleBuffer;
_ofn.nMaxFileTitle = _MAX_PATH + 1;
_ofn.lpstrInitialDir = _directoryBuffer;
_ofn.lpstrFilter = Marshal.StringToCoTaskMemUni(String.Format(CultureInfo.InvariantCulture, "txt \0*.txt"));
string title = String.Format(CultureInfo.InvariantCulture, "title");
_ofn.lpstrTitle = Marshal.StringToCoTaskMemUni(title);
_ofn.lpfnHook = new OfnHookProc(MyHookProc);
}
public bool Show()
{
User32.GetOpenFileName(ref _ofn);
return true;
}
public IntPtr MyHookProc(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)] int msg, IntPtr wParam, IntPtr lParam)
{
...
}

I found the solution my self.
Please try to use CommonOpenFileDialog or CommonSaveFileDialog in Windows7APICodePack. https://www.nuget.org/packages/Windows7APICodePack-Shell/
refers
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/3b55d433-b1e3-4943-ba28-69c72b613c91/get-folder-name-from-browserdialog-in-wpf-c?forum=wpf
https://github.com/Corillian/Windows-API-Code-Pack-1.1
It is really easy to implement with the package.
Here is an example to add controls.
public static CommonOpenFileDialog OpenFileDialog(string title, List<CommonFileDialogFilter> filters, string initialDirectory = "", bool multiselect = false)
{
var openFilerDialog = new CommonOpenFileDialog();
openFilerDialog.EnsureReadOnly = true;
openFilerDialog.IsFolderPicker = false;
openFilerDialog.AllowNonFileSystemItems = false;
openFilerDialog.Multiselect = multiselect;
openFilerDialog.Title = title;
if (filters != null)
{
foreach (var filter in filters)
{
openFilerDialog.Filters.Add(filter);
}
}
if (!string.IsNullOrEmpty(initialDirectory))
{
openFilerDialog.InitialDirectory = initialDirectory; // Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
}
return openFilerDialog;
}
private void CustomOpenFileDialog_Click(object sender, RoutedEventArgs e)
{
var dialog = FileDialog.OpenFileDialog("Custom OpenFileDialog", new List<CommonFileDialogFilter>() { new CommonFileDialogFilter("stl", "*.stl") });
AddOpenFileDialogCustomControls(dialog);
var dialogResult = dialog.ShowDialog();
}
public static void AddOpenFileDialogCustomControls(CommonFileDialog openDialog)
{
// Add a RadioButtonList
CommonFileDialogRadioButtonList list = new CommonFileDialogRadioButtonList("radioButtonOptions");
list.Items.Add(new CommonFileDialogRadioButtonListItem("Option A"));
list.Items.Add(new CommonFileDialogRadioButtonListItem("Option B"));
list.SelectedIndex = 1;
openDialog.Controls.Add(list);
}

Related

How to correct hit test area for list view items with only an image (null label text)

I have a System.Windows.Forms.ListView with icons and empty string labels. Here is the code that creates and fills the list view:
listView1 = new System.Windows.Forms.ListView();
listView1.BackColor = System.Drawing.Color.Blue;
listView1.BorderStyle = System.Windows.Forms.BorderStyle.None;
listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
listView1.HideSelection = false;
listView1.Location = new System.Drawing.Point(93, 66);
listView1.MultiSelect = false;
listView1.Name = "listView1";
listView1.ShowItemToolTips = true;
listView1.Size = new System.Drawing.Size(434, 332);
listView1.TabIndex = 0;
listView1.UseCompatibleStateImageBehavior = false;
var images = Directory.GetFiles
(#"my path")
.Where((where) => Path.GetExtension(where)
.Equals(".PNG", StringComparison.CurrentCultureIgnoreCase))
.Select((selected)
=> Image.FromFile(selected));
var il = new ImageList();
il.ImageSize = new Size(75, 75);
il.Images.AddRange(images.ToArray());
listView1.LargeImageList = il;
for (int i = 0; i < il.Images.Count; i++)
{
var lvi = new ListViewItem("", i)
{
ToolTipText = i.ToString()
};
listView1.Items.Add(lvi);
}
Controls.Add(listView1);
Now I'm using the technique described in many places, like here, to set the list view item image spacing:
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
public int MakeLong(short lowPart, short highPart)
{
return (int)(((ushort)lowPart) | (uint)(highPart << 16));
}
public void ListViewItem_SetSpacing(ListView listview, short leftPadding, short topPadding)
{
const int LVM_FIRST = 0x1000;
const int LVM_SETICONSPACING = LVM_FIRST + 53;
SendMessage(listview.Handle, LVM_SETICONSPACING, IntPtr.Zero, (IntPtr)MakeLong(leftPadding, topPadding));
}
The problem is that the hit test area still includes the label, even though there is no label, so the wrong item is returned by the hit test and the wrong tool tip is displayed when the mouse is over where the label of the adjacent item would be:
Here is what the "wrong" hit test looks like.
private void ListView1_MouseDown(object sender, MouseEventArgs e)
{
var hti = listView1.HitTest(e.Location);
}
Is there a way to remove the label from a list view item so the hit test area only includes the image? Or am I forced to go the OwnerDraw = true; route (which I understand is very tricky and/or impossible)?

Inserting a control into another control at specific location?

I am working with win forms. I have two forms : my main form, Form1 and a Form I made called TextBlock. I am making a text editor, where you can place text boxes around a page, and edit them (think word).
Here are my two forms.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
saveFileDialog.Filter = "Text File|*.txt";
var result = saveFileDialog.ShowDialog();
if (result == DialogResult.OK)
{
StreamWriter writer = new
StreamWriter(saveFileDialog.OpenFile());
writer.Write(tb_Main.Text);
writer.Dispose();
writer.Close();
}
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
}
private void button_tb_Click(object sender, EventArgs e)
{
TextBlock tb_edit = new TextBlock();
tb_edit.Text = "New Text Block";
// tb_edit.Multiline = true;
// tb_edit.Size = new Size(100,100);
// tb_edit.MinimumSize = new Size(50, 50);
tb_edit.form1 = this;
tb_edit.TopLevel = false;
tb_edit.btn_accepttb.BringToFront();
tb_Main.Controls.Add(tb_edit);
tb_edit.Show();
tb_edit.BringToFront();
}
}
and my custom form here:
public partial class TextBlock : Form
{
public Form1 form1;
public TextBlock()
{
InitializeComponent();
}
private void btn_accepttb_Click(object sender, EventArgs e)
{
TextBox tb_edit = new TextBox();
tb_edit.Text = "New Text Block";
tb_edit.Multiline = true;
tb_edit.Size = this.Size;
int dif = form1.tb_Main.Lines.Count()*(int)tb_edit.Font.Size;
Point loca = new Point(this.Location.X,this.Location.Y+dif);
tb_edit.Location = this.Location;
form1.tb_Main.Controls.Add(tb_edit);
tb_edit.Show();
tb_edit.BringToFront();
form1.tb_Main.Controls.Remove(this);
}
}
What it does: it makes a copy my TextBlock, for placement and resizing purposes. when you have it where you want and how big you want, you click the button, and it replaces itself with a regular textbox, of that size, in that position.
What I want it to do: currently it is working with one exception. I am adding it to the controls, of tb_Main (my main textbox, it takes up the whole form) in Form1, it shows up. its the right size, except when i fill tb_Main with text, and i scroll, the new textbox stays where it is while its parent scrolls behind it.
Question : if I scroll down into my document and decide I want this textbox here, how do I ensure its position relative to the scroll of the textbox im putting it in. so when I scroll on, it basically stays embedded in the page where I put it (when I say "page" im referring to my tb_Main).
It is better to create a richtextbox instead of textbox. It has all capabilities of textbox and way more. This example works only with a richtextbox.
Subclassed richtextbox:
class MyRichTextBox : RichTextBox {
[DllImport( "user32.dll" )]
private static extern bool GetScrollInfo( IntPtr hwnd, SBOrientation fnBar,
ref SCROLLINFO lpsi );
[StructLayout( LayoutKind.Sequential )]
private struct SCROLLINFO {
public uint cbSize;
public ScrollInfoMask fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
}
private enum ScrollInfoMask : uint {
SIF_RANGE = 0x1,
SIF_PAGE = 0x2,
SIF_POS = 0x4,
SIF_DISABLENOSCROLL = 0x8,
SIF_TRACKPOS = 0x10,
SIF_ALL = ( SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS ),
}
private enum SBOrientation : int {
SB_HORZ = 0x0,
SB_VERT = 0x1,
}
private const int WM_VSCROLL = 0x115;
private const int SB_LINEUP = 0;
private const int SB_LINEDOWN = 1;
private const int SB_PAGEUP = 2;
private const int SB_PAGEDOWN = 3;
private const int SB_THUMBPOSITION = 4;
private const int SB_THUMBTRACK = 5;
private const int SB_TOP = 6;
private const int SB_BOTTOM = 7;
private const int SB_ENDSCROLL = 8;
private bool isThumbTrack = false;
private TextBox childTextbox = null;
private int scrollPos = 0;
public MyTextBox( TextBox textbox ) { //here you pass the child textbox you want to scroll
childTextbox = textbox;
}
protected override void OnVScroll( EventArgs e ) {
if( childTextbox == null ) { base.OnVScroll( e ); return; }
SCROLLINFO si = new SCROLLINFO();
si.cbSize = (uint)Marshal.SizeOf( si );
si.fMask = ScrollInfoMask.SIF_ALL;
GetScrollInfo( this.Handle, SBOrientation.SB_VERT, ref si );
//there is a difference when the user uses the thumb to get scroll pos.
//When user uses the thumb we get *nTrackPos* otherwise *nPos*
if( isThumbTrack == true ) {
childTextbox.Location = new Point( childTextbox.Location.X, childTextbox.Location.Y -
(si.nTrackPos - scrollPos ) );
isThumbTrack = false;
scrollPos = si.nTrackPos;
}
else {
childTextbox.Location = new Point( childTextbox.Location.X, childTextbox.Location.Y -
( si.nPos - scrollPos ) );
scrollPos = si.nPos;
}
base.OnVScroll( e );
}
protected override void WndProc( ref Message m ) {
int wParam;
if(m.Msg == WM_VSCROLL ) {
wParam = m.WParam.ToInt32();
wParam &= 0xFFFF; //get low 16 bits of wParam
//Check if user is using the thumb to scroll
if( wParam == SB_THUMBTRACK ) {
isThumbTrack = true;
}
}
base.WndProc( ref m );
}
}

How to load lots of icons into ListView quickly from files dragged & dropped?

I would like to load the icons from multiple files dragged onto a listview and some of the information of those files, but the process is going very slow.
In my test, a list of 381 files dragged (some are not exe so those are skipped in my code), takes over 2 minutes to load the icon from the file, and add them to the listview.
Following is condensed version of my code :
public Form1()
{
InitializeComponent();
listView1.DragEnter += ListView1_DragEnter;
listView1.DragDrop += ListView1_DragDrop;
listView1.LargeImageList = new ImageList() { ImageSize = new Size( 64, 64) };
listView1.SmallImageList = new ImageList();
listView1.AllowDrop = true;
}
private void ListView1_DragDrop(object sender, DragEventArgs e)
{
if(e.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] values = (string[])e.Data.GetData(DataFormats.FileDrop);
Convert.IconExtractor i = new Convert.IconExtractor();
foreach (var v in values)
{
var info = new FileInfo(v);
if(info.Extension.ToLower() == ".exe")
{
ListViewItem item = new ListViewItem();
listView1.LargeImageList.Images.Add(i.Extract(info.FullName, Convert.IconSize.Large));
listView1.SmallImageList.Images.Add(i.Extract(info.FullName, Convert.IconSize.Small));
item.Text = Path.GetFileNameWithoutExtension(info.FullName);
item.ImageIndex = listView1.SmallImageList.Images.Count -1;
item.Tag = info.FullName;
listView1.Items.Add(item);
}
}
listView1.Refresh();
}
}
private void ListView1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.All;
}
}
The method used for extraction is pasted here for convenience :
public enum IconSize
{
Small,
Large
}
public class IconExtractor
{
//----------------------------------------------------------------------------
//
// Description: Extracts the icon associated with any file on your system.
// Author: WidgetMan http://softwidgets.com
//
// Remarks...
//
// Class requires the IconSize enumeration that is implemented in this
// same file. For best results, draw an icon from within a control's Paint
// event via the e.Graphics.DrawIcon method.
//
//----------------------------------------------------------------------------
private const int SHGFI_ICON = 0x100;
private const int SHGFI_SMALLICON = 0x1;
private const int SHGFI_LARGEICON = 0x0;
private struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public int dwAttributes;
[VBFixedString(260), MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[VBFixedString(80), MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
}
[DllImport("shell32", EntryPoint = "SHGetFileInfoA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int SHGetFileInfo(string pszPath, int dwFileAttributes, ref SHFILEINFO psfi, int ByValcbFileInfo, int uFlags);
public IconExtractor()
{
}
public System.Drawing.Icon Extract(string File, IconSize Size)
{
SHFILEINFO aSHFileInfo = default(SHFILEINFO);
int cbFileInfo = 0;
int uflags = 0;
System.Drawing.Icon Icon = default(System.Drawing.Icon);
switch (Size)
{
case IconSize.Large:
uflags = SHGFI_ICON | SHGFI_LARGEICON;
break;
default:
uflags = SHGFI_ICON | SHGFI_SMALLICON;
break;
}
cbFileInfo = Marshal.SizeOf(aSHFileInfo);
SHGetFileInfo(File, 0, ref aSHFileInfo, cbFileInfo, uflags);
Icon = System.Drawing.Icon.FromHandle(aSHFileInfo.hIcon);
return Icon;
}
public System.Drawing.Icon Extract(string File)
{
return this.Extract(File, IconSize.Small);
}
}
}
What can I do to make this process quick. The concept is to make a quick launcher for multiple applications.
Also of note, while this process is happening, the drag-collection icon is still 'hung' on windows explorer until the drag & drop task has completed fully (looped through all the files).
Here is a rough draft to give a visual of the application:
(yes, i know the icons extracted look like crap as well, but I think that is a separate issue from the slow issue I am having)
My advice is not to load all 381 icons in one step, particularly if the items are not visible. Load them on demand as items are scrolled into view, of if the view is large enough, load them in the background using your threading/task/concurrency technology of choice.
That's what Windows does.
To speed up loading, you may want to use the System Image List which would most likely benefit from caching. Here's some code for getting the large icon. Just change size to be SHGFI_ICON for your use.
public static Icon GetLargeIcon(string FileName, bool jumbo, bool useFileAttributes=false)
{
var shinfo = new SHFILEINFO();
uint flags;
flags = SHGFI_SYSICONINDEX;
if (useFileAttributes)
{
flags |= SHGFI_USEFILEATTRIBUTES;
}
var res = SHGetFileInfo(FileName, FILE_ATTRIBUTE_NORMAL, ref shinfo, (uint) Marshal.SizeOf(shinfo), flags);
if (res == IntPtr.Zero)
{
throw (new FileNotFoundException());
}
var iconIndex = shinfo.iIcon;
// Get the System IImageList object from the Shell:
var iidImageList = new Guid("46EB5926-582E-4017-9FDF-E8998DAA0950");
IImageList iml;
var size = jumbo
? SHIL_JUMBO
: SHIL_EXTRALARGE;
var hres = SHGetImageList(size, iidImageList, out iml);
if (hres != 0)
{
throw (new Exception("Error SHGetImageList"));
}
IntPtr hIcon;
const int ILD_TRANSPARENT = 1;
hres = iml.GetIcon(iconIndex, ILD_TRANSPARENT, out hIcon);
var icon = Icon.FromHandle(hIcon);
icon = icon.Clone() as Icon;
var bm = icon.ToBitmap();
DestroyIcon(hIcon);
return icon;
}

Spy++ doesn't reach button in Qt application

I'm trying to get the properties of a button but when I drag the spy++'s find window tool it doesn't reach the button (of caption "iniciar gravação" in that case) but rather the button grid parent, like this:
Why is that and how can I get the button properties? I tried with auto it info tool but I get the same behavior.
I tried get that button properties from C# code, like this:
public class WindowHandleInfo
{
private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);
private IntPtr _MainHandle;
public WindowHandleInfo(IntPtr handle)
{
this._MainHandle = handle;
}
public List<IntPtr> GetAllChildHandles()
{
List<IntPtr> childHandles = new List<IntPtr>();
GCHandle gcChildhandlesList = GCHandle.Alloc(childHandles);
IntPtr pointerChildHandlesList = GCHandle.ToIntPtr(gcChildhandlesList);
try
{
EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
EnumChildWindows(this._MainHandle, childProc, pointerChildHandlesList);
}
finally
{
gcChildhandlesList.Free();
}
return childHandles;
}
private bool EnumWindow(IntPtr hWnd, IntPtr lParam)
{
GCHandle gcChildhandlesList = GCHandle.FromIntPtr(lParam);
if (gcChildhandlesList == null || gcChildhandlesList.Target == null)
{
return false;
}
List<IntPtr> childHandles = gcChildhandlesList.Target as List<IntPtr>;
childHandles.Add(hWnd);
return true;
}
}
void printWindows(IntPtr parent, int tabLevel)
{
var w = new WindowHandleInfo(parent);
foreach (IntPtr h in w.GetAllChildHandles())
{
string caption = GetTextBoxText(h) ?? "not found";
Debug.Write(new string('\t', tabLevel));
Debug.WriteLine(caption);
printWindows(h, tabLevel + 1);
}
}
int GetTextBoxTextLength(IntPtr hTextBox)
{
// helper for GetTextBoxText
const int WM_GETTEXTLENGTH = 0x000E;
int result = SendMessage(hTextBox, WM_GETTEXTLENGTH, 0, IntPtr.Zero);
return result;
}
string GetTextBoxText(IntPtr hTextBox)
{
const int WM_GETTEXT = 0x000D;
int len = GetTextBoxTextLength(hTextBox);
if (len <= 0) return null; // no text
StringBuilder sb = new StringBuilder(len + 1);
SendMessage(hTextBox, WM_GETTEXT, len + 1, sb);
return sb.ToString();
}
using like this:
IntPtr parent = FindWindow(IntPtr.Zero, "my app title");
printWindows(parent, 0);
But I can't see anyhing related to Iniciar gravação button.
Qt UI controls (widgets, in Qt lexicon. Aka buttons, line edits, comboboxes, etc.) are not backed by native controls. They just steal the native UI look and feel from them and mimic it.
For this reason, you won't find those controls using some of those "spy" tools -- you may still find them through accessibility, though (*).
Or, you can inspect your application using other Qt-specific tools, such as GammaRay for debugging or Squish for UI testing.
(*) controls shipped with Qt are accessibile, but if someone manually reimplements something that looks like a button and doesn't provide it with accessibility then you can't do much about that.

Taskbar location

How can i detect where the taskbar is located? I need to know for displaying my notification in the right corner. Thanks
Edit:
Thank you Hans Passant. I used that with this to get location. I hope is ok.
GetTaskbarLocation(TaskbarPosition.GetTaskbarPosition());
private void GetTaskbarLocation(Rectangle rc)
{
if (rc.X == rc.Y)
{
if (rc.Right < rc.Bottom)
taskbarLocation = TaskbarLocation.Left;
if (rc.Right > rc.Bottom)
taskbarLocation = TaskbarLocation.Top;
}
if (rc.X > rc.Y)
taskbarLocation = TaskbarLocation.Right;
if (rc.X < rc.Y)
taskbarLocation = TaskbarLocation.Bottom;
}
public static Rectangle GetTaskbarPosition() {
var data = new APPBARDATA();
data.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(data);
IntPtr retval = SHAppBarMessage(ABM_GETTASKBARPOS, ref data);
if (retval == IntPtr.Zero) throw new Win32Exception("Please re-install Windows");
return new Rectangle(data.rc.left, data.rc.top,
data.rc.right - data.rc.left, data.rc.bottom - data.rc.top);
}
// P/Invoke goo:
private const int ABM_GETTASKBARPOS = 5;
[System.Runtime.InteropServices.DllImport("shell32.dll")]
private static extern IntPtr SHAppBarMessage(int msg, ref APPBARDATA data);
private struct APPBARDATA {
public int cbSize;
public IntPtr hWnd;
public int uCallbackMessage;
public int uEdge;
public RECT rc;
public IntPtr lParam;
}
private struct RECT {
public int left, top, right, bottom;
}
SHAppBarMessage(ABM_GETTASKBARPOS)
See the SHAppBarMessage Function and the ABM_GETTASKBARPOS Message for more info and the pinvoke page for SHAppBarMessage has a VB.Net sample that shouldn't be too difficult to translate.
The SHAppBarMessage function will return you information about the taskbar if you pass in the ABM_GETTASKBARPOS message. It has an out parameter which is a pointer to APPBARDATA that contains the screen cooridinates of the task bar. You can use to work out where on screen it is.
It's probably best to use the available API: NotifyIcon.ShowBalloonTip:
void Form1_DoubleClick(object sender, EventArgs e)
{
notifyIcon1.Visible = true;
notifyIcon1.ShowBalloonTip(20000, "Information", "This is the text",
ToolTipIcon.Info );
}
In Java, using JNA (adapted from other C# solutions above)
public static Rectangle getTaskbarPosition() throws Exception {
APPBARDATA data = new APPBARDATA();
data.cbSize = new WinDef.DWORD(data.size());
WinDef.UINT_PTR retval = Shell32.INSTANCE.SHAppBarMessage(ABM_GETTASKBARPOS, data);
if (retval == null) {
throw new Exception("Please re-install Windows");
}
return new Rectangle(data.rc.left, data.rc.top, data.rc.right - data.rc.left, data.rc.bottom - data.rc.top);
}

Categories