I AM new to wpf can you please tell me how to change desktop wallpaper by code.
i have read few topics over this but i cant seem to come up with the solution in WPF.
The problem is the desktop Wallpaper Does not changes when i call SetWallpaper.
Below is make code:
public static ArrayList images;
const int SPI_SETDESKWALLPAPER = 20;
const int SPIF_UPDATEINIFILE = 0x01;
const int SPIF_SENDWININICHANGE = 0x02;
public enum StyleS_Wallpaper : int
{
Tiled, Centered, Stretched
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern int SystemParametersInfo(
int uAction, int uParam, string lpvParam, int fuWinIni);
private void OpenExecuted(object sender, ExecutedRoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.InitialDirectory = "c:\\";
ofd.Multiselect = true;
ofd.Filter = "Image Files (*.jpg)|*.jpg|Image Files (*.png)|*.png|Image File (*.gif)|*.gif|Image File (*.bmp)|*.bmp|Image Files (*.png)|*.png";
//ofd.RestoreDirectory = true;
Nullable<bool> result = ofd.ShowDialog();
if (result == true)
{
FileNames = ofd.FileNames;
if (images == null)
{
images = new ArrayList();
newlist = new List<string>();
}
for (int i = 0; i < FileNames.Length; i++)
{
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.UriSource = new Uri(FileNames[i]);
bitmap.EndInit();
images.Add(bitmap);
newlist.Add(FileNames[i]);
NextCount++;
}
}
}
public void SetWallpaper(string path,StyleS_Wallpaper selected)
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(#"Control Panel\Desktop", true);
if (selected == StyleS_Wallpaper.Stretched)
{
key.SetValue(#"WallpaperStyle", 2.ToString());
key.SetValue(#"TileWallpaper", 0.ToString());
}
if (selected == StyleS_Wallpaper.Centered)
{
key.SetValue(#"WallpaperStyle", 1.ToString());
key.SetValue(#"TileWallpaper", 0.ToString());
}
if (selected == StyleS_Wallpaper.Tiled)
{
key.SetValue(#"WallpaperStyle", 1.ToString());
key.SetValue(#"TileWallpaper", 1.ToString());
}
SystemParametersInfo(SPI_SETDESKWALLPAPER,
0,
path,
SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
}
private void CenterImage_Click(object sender, RoutedEventArgs e)
{
BitmapImage img = (BitmapImage)images[currentPicture];
string Path = img.UriSource.ToString();
string name = "0";
// TrimingString Returns the string path as C:\Documents and Settings\ProZec\Desktop\WallPapers
TrimingString(Path, ref name, true);
SetWallpaper(name, StyleS_Wallpaper.Centered);
}
Are you using a BMP file? If not, you should try converting it first before using SPI_SETDESKWALLPAPER.
WPF really has nothing to do with this. Setting the desktop background is just plain C# and Windows API work.
Related
I have made a recorder program that takes screenshots and, in the end, combines them into an mp4 video. The program now works by capturing the whole screen. What I need to do is to allow the user to select a window to record from. Is there a way to use the handle to record only that window?
Forms1.cs[Design]
The Recorder script is bellow
class Recorder
{
public static int userwidth = 1;
public static int userhight = 1;
public static int v=0;
//Video variables:
public static Rectangle bounds;
private string outputPath = "";
private string tempPath = "";
private int fileCount = 1;
private List<string> inputImageSequence = new List<string>();
//File variables:
private string audioName = "mic.wav";
private string videoName = "video.mp4";
private string finalName = "FinalVideo.mp4-";
//Time variable:
Stopwatch watch = new Stopwatch();
//Audio variables:
public static class NativeMethods
{
[DllImport("winmm.dll", EntryPoint = "mciSendStringA", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
public static extern int record(string lpstrCommand, string lpstrReturnString, int uReturnLength, int hwndCallback);
}
//ScreenRecorder Object:
public ScreenRecorder(Rectangle b, string outPath)
{
//Create temporary folder for screenshots:
CreateTempFolder("tempScreenCaps");
//Set variables:
bounds = b;
outputPath = outPath;
}
//Create temporary folder:
private void CreateTempFolder(string name)
{
//Check if a C or D drive exists:
if (Directory.Exists("D://"))
{
string pathName = $"D://{name}";
Directory.CreateDirectory(pathName);
tempPath = pathName;
}
else
{
string pathName = $"C://Documents//{name}";
Directory.CreateDirectory(pathName);
tempPath = pathName;
}
}
//Change final video name:
public void setVideoName(string name)
{
finalName = name;
}
//Delete all files and directory:
private void DeletePath(string targetDir)
{
string[] files = Directory.GetFiles(targetDir);
string[] dirs = Directory.GetDirectories(targetDir);
//Delete each file:
foreach (string file in files)
{
File.SetAttributes(file, FileAttributes.Normal);
File.Delete(file);
}
//Delete the path:
foreach (string dir in dirs)
{
DeletePath(dir);
}
Directory.Delete(targetDir, false);
}
//Delete all files except the one specified:
private void DeleteFilesExcept(string targetDir, string excDir)
{
string[] files = Directory.GetFiles(targetDir);
//Delete each file except specified:
foreach (string file in files)
{
if (file != excDir)
{
File.SetAttributes(file, FileAttributes.Normal);
File.Delete(file);
}
}
}
//Clean up program on crash:
public void cleanUp()
{
if (Directory.Exists(tempPath))
{
DeletePath(tempPath);
}
}
//Return elapsed time:
public string getElapsed()
{
return string.Format("{0:D2}:{1:D2}:{2:D2}", watch.Elapsed.Hours, watch.Elapsed.Minutes, watch.Elapsed.Seconds);
}
//Record video:
public void RecordVideo()
{
//Keep track of time:
watch.Start();
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(new Point(bounds.Left, bounds.Top), Point.Empty, bounds.Size);
}
//Save screenshot:
string name = tempPath + "//screenshot-" + fileCount + ".png";
bitmap.Save(name, ImageFormat.Png);
inputImageSequence.Add(name);
fileCount++;
//Dispose of bitmap:
bitmap.Dispose();
}
}
//Compare images
public static List<bool> GetHash(Bitmap bmpSource)
{
List<bool> lResult = new List<bool>();
//create new image with 16x16 pixel
Bitmap bmpMin = new Bitmap(bmpSource, new System.Drawing.Size(128,128));
for (int j = 0; j < bmpMin.Height; j++)
{
for (int i = 0; i < bmpMin.Width; i++)
{
//reduce colors to true / false
lResult.Add(bmpMin.GetPixel(i, j).GetBrightness() < 0.5f);
}
}
return lResult;
}
//Record audio:
public void RecordAudio()
{
NativeMethods.record("open new Type waveaudio Alias recsound", "", 0, 0);
NativeMethods.record("record recsound", "", 0, 0);
}
//Save audio file:
private void SaveAudio()
{
string audioPath = "save recsound " + outputPath + "//" + audioName;
NativeMethods.record(audioPath, "", 0, 0);
NativeMethods.record("close recsound", "", 0, 0);
}
//Save video file:
public void SaveVideo(int width, int height, int frameRate)
{
for(int k=1; k > fileCount; k++)
{
List<bool> iHash1 = GetHash(new Bitmap(tempPath + "//screenshot-" + k + ".png"));
List<bool> iHash2 = GetHash(new Bitmap(tempPath + "//screenshot-" + (k + 1) + ".png"));
//determine the number of equal pixel (x of256)
long equalElements = iHash1.Zip(iHash2, (i, j) => i == j).Count(eq => eq);
if (equalElements > 16380)
{
var filePath = tempPath + "//screenshot-" + k + ".png";
File.Delete(filePath);
}
}
using (VideoFileWriter vFWriter = new VideoFileWriter())
{
vFWriter.Open(outputPath + "//"+ videoName, width, height, frameRate, VideoCodec.MPEG4 );
//Make each screenshot into a video frame:
foreach (string imageLocation in inputImageSequence)
{
Bitmap imageFrame = System.Drawing.Image.FromFile(imageLocation) as Bitmap;
vFWriter.WriteVideoFrame(imageFrame);
imageFrame.Dispose();
}
//Close:
vFWriter.Close();
}
}
//Combine video and audio files:
private void CombineVideoAndAudio(string video, string audio)
{
//FFMPEG command to combine video and audio:
string args = $"/c ffmpeg -i \"{video}\" -i \"{audio}\" -shortest {finalName}";
ProcessStartInfo startInfo = new ProcessStartInfo
{
CreateNoWindow = false,
FileName = "cmd.exe",
WorkingDirectory = outputPath,
Arguments = args
};
//Execute command:
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
}
}
public void Stop()
{
//Stop watch:
watch.Stop();
//Video variables:
int width = bounds.Width;
int height = bounds.Height;
int frameRate =v+10;
//Save audio:
SaveAudio();
//Save video:
SaveVideo(width, height, frameRate);
//Combine audio and video files:
CombineVideoAndAudio(videoName, audioName);
//Delete the screenshots and temporary folder:
DeletePath(tempPath);
//Delete separated video and audio files:
DeleteFilesExcept(outputPath, outputPath + "\\" + finalName);
}
}
As Ryan said in the comments, if you see the Get a screenshot of a specific application the code that actually works is the one below:
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
private static extern int SetForegroundWindow(IntPtr hWnd);
private const int SW_RESTORE = 9;
[DllImport("user32.dll")]
private static extern IntPtr ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect);
public Bitmap CaptureApplication(string procName)
{
Process proc;
// Cater for cases when the process can't be located.
try
{
proc = Process.GetProcessesByName(procName)[0];
}
catch (IndexOutOfRangeException e)
{
return null;
}
// You need to focus on the application
SetForegroundWindow(proc.MainWindowHandle);
ShowWindow(proc.MainWindowHandle, SW_RESTORE);
// You need some amount of delay, but 1 second may be overkill
Thread.Sleep(1000);
Rect rect = new Rect();
IntPtr error = GetWindowRect(proc.MainWindowHandle, ref rect);
// sometimes it gives error.
while (error == (IntPtr)0)
{
error = GetWindowRect(proc.MainWindowHandle, ref rect);
}
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
Graphics.FromImage(bmp).CopyFromScreen(rect.left,rect.top,0,0,new Size(width, height),CopyPixelOperation.SourceCopy);
return bmp;
}
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)?
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;
}
I want to have an custom OpenFileDialog form within my project where I can add/remove buttons and customize whatever I want like a normal form. This is mainly so that it fits into the theme I am using, additionally, I can add custom buttons. Is there any tutorials on how I could construct my own? Are there any pre-existing projects I can use straight out of the download?
I hope that will fit your requirements:
You will need one TreeView and an ImageList
Code
You will need System.Runtime.InteropServices;
And following code to get the associated icon from the path:
[StructLayout(LayoutKind.Sequential)]
public struct SHFILEINFO
{
public IntPtr hIcon;
public IntPtr iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
class Win32
{
public const uint SHGFI_ICON = 0x100;
public const uint SHGFI_LARGEICON = 0x0; // 'Large icon
public const uint SHGFI_SMALLICON = 0x1; // 'Small icon
[DllImport("shell32.dll")]
public static extern IntPtr SHGetFileInfo(string pszPath,
uint dwFileAttributes,
ref SHFILEINFO psfi,
uint cbSizeFileInfo,
uint uFlags);
}
private int GetIconOfFile_Folder(string Path)
{
IntPtr hImgSmall; //the handle to the system image list
IntPtr hImgLarge; //the handle to the system image list
string fName; // 'the file name to get icon from
SHFILEINFO shinfo = new SHFILEINFO();
//Use this to get the small Icon
hImgSmall = Win32.SHGetFileInfo(Path, 0, ref shinfo,
(uint)Marshal.SizeOf(shinfo),
Win32.SHGFI_ICON |
Win32.SHGFI_SMALLICON);
//Use this to get the large Icon
//hImgLarge = SHGetFileInfo(fName, 0,
//ref shinfo, (uint)Marshal.SizeOf(shinfo),
//Win32.SHGFI_ICON | Win32.SHGFI_LARGEICON);
//The icon is returned in the hIcon member of the shinfo
//struct
System.Drawing.Icon myIcon =
System.Drawing.Icon.FromHandle(shinfo.hIcon);
imageList1.Images.Add(myIcon);
return imageList1.Images.Count - 1;
}
Use following Method to Get all your Drives (best place it in your constructor/Form_Load):
private void GetAllDrives()
{
DriveInfo[] drives = DriveInfo.GetDrives();
foreach (var drive in drives)
{
TreeNode rootTreeNode = new TreeNode();
rootTreeNode.Text = drive.Name;
rootTreeNode.Tag = drive.Name;
rootTreeNode.ImageIndex = GetIconOfFile_Folder(drive.Name);
rootTreeNode.SelectedImageIndex = rootTreeNode.ImageIndex;
rootTreeNode.Nodes.Add(" "); //Placeholder to enable expanding (+)
treeView1.Nodes.Add(rootTreeNode);
}
}
Then you will need an EventHandler for the Expand-Event, which will call the method GetFilesAndFolder()
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
e.Node.Nodes.Clear();
GetFilesAndFolder(e.Node, (string)e.Node.Tag);
}
private void GetFilesAndFolder(TreeNode tn, string Path)
{
try
{
string[] Directories = Directory.GetDirectories(Path);
string[] Files = Directory.GetFiles(Path);
foreach (string dir in Directories)
{
TreeNode dirTreeNode = new TreeNode();
dirTreeNode.Tag = dir;
dirTreeNode.Text = new DirectoryInfo(dir).Name;
dirTreeNode.ImageIndex = GetIconOfFile_Folder(dir);
dirTreeNode.SelectedImageIndex = dirTreeNode.ImageIndex;
dirTreeNode.Nodes.Add(" ");
tn.Nodes.Add(dirTreeNode);
}
foreach (string file in Files)
{
TreeNode fileTreeNode = new TreeNode();
fileTreeNode.Tag = file;
fileTreeNode.Text = new FileInfo(file).Name;
fileTreeNode.ImageIndex = GetIconOfFile_Folder(file);
fileTreeNode.SelectedImageIndex = fileTreeNode.ImageIndex;
tn.Nodes.Add(fileTreeNode);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
Finally I have created an EventHandler for the NodeDoubleClick-Event in the TreeView:
private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (CheckIfPathIsFile(e.Node.Tag.ToString()) == true) //If the Tag (Path) is a File
{
//Do something with the Path (close this Form + return Path)
}
}
private bool CheckIfPathIsFile(string Path)
{
// get the file attributes for file or directory
FileAttributes attr = File.GetAttributes(Path);
//detect whether its a directory or file
if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
return false;
else
return true;
}
If you used WinForms, chances are that at some point you wanted to extend the OpenFileDialog or SaveFileDialog, but you gave up because there is no easy way to do it,Go with following link to get undestand how to custermize with your own...
HERE
Is it possible to draw a WebBrowser.Document to a Bitmap? Basically taking a screenshot of a WebBrowser control (note, this is with a WebBrowser that doesn't live on a form, but just in code).
WebBrowser w = new WebBrowser();
w.Document = "<b>Hello</b> world.";
w.Document.DrawToBitmap ???
Thanks!
I use the following code to capture a screenshot of a web page loaded in a WebBrowser control:
class NativeMethods
{
[ComImport]
[Guid("0000010D-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IViewObject
{
void Draw([MarshalAs(UnmanagedType.U4)] uint dwAspect, int lindex, IntPtr pvAspect, [In] IntPtr ptd, IntPtr hdcTargetDev, IntPtr hdcDraw, [MarshalAs(UnmanagedType.Struct)] ref RECT lprcBounds, [In] IntPtr lprcWBounds, IntPtr pfnContinue, [MarshalAs(UnmanagedType.U4)] uint dwContinue);
}
[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public static void GetImage(object obj, Image destination, Color backgroundColor)
{
using(Graphics graphics = Graphics.FromImage(destination))
{
IntPtr deviceContextHandle = IntPtr.Zero;
RECT rectangle = new RECT();
rectangle.Right = destination.Width;
rectangle.Bottom = destination.Height;
graphics.Clear(backgroundColor);
try
{
deviceContextHandle = graphics.GetHdc();
IViewObject viewObject = obj as IViewObject;
viewObject.Draw(1, -1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, deviceContextHandle, ref rectangle, IntPtr.Zero, IntPtr.Zero, 0);
}
finally
{
if(deviceContextHandle != IntPtr.Zero)
{
graphics.ReleaseHdc(deviceContextHandle);
}
}
}
}
}
Example:
Bitmap screenshot = new Bitmap(1024, 768);
NativeMethods.GetImage(webBrowser.ActiveXInstance, screenshot, Color.White);
public void HTMLScreenShot()
{
WebBrowser wb = new WebBrowser();
wb.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(wb_DocumentCompleted);
wb.Size = new Size(800, 600);
// Add html as string
wb.Navigate("about:blank");
wb.Document.Write("<b>Hellow World!</b>");
// Add html from website
// wb.Navigate("http://myurl.com");
}
void wb_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser wb = sender as WebBrowser;
using (Bitmap bitmap = new Bitmap(wb.Width, wb.Height))
{
Rectangle bounds = new Rectangle(new Point(0, 0), wb.Size);
wb.DrawToBitmap(bitmap, bounds);
bitmap.Save("C:\WebsiteScreenshot.png");
}
}
http://www.bryancook.net/2006/03/screen-capture-for-invisible-windows.html
and here:
http://www.codeproject.com/KB/graphics/screen_capturing.aspx
I believe you should get the handle of your WebBrowser control and save it's content as image like suggested in those links.
//
// If you want to take a snap from existing webBrowser Control
//
private void button1_Click(object sender, EventArgs e)
{
using (FileDialog fd = new SaveFileDialog())
{
fd.Filter = "Image (*.png)|*.png";
if (fd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
new WebPageSnap(webBrowser1.Url.ToString(), fd.FileName);
//might take 3 or 4 seconds to save cauz it has to load again.
}
}
}
//
// Or if you want to take a snap without showing up
//
private void button2_Click(object sender, EventArgs e)
{
using (FileDialog fd = new SaveFileDialog())
{
fd.Filter = "Image (*.png)|*.png";
if (fd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string url = "http://www.google.com";
// or
url = textBox1.Text;
new WebPageSnap(url, fd.FileName); }
}
}
class WebPageSnap
{
WebBrowser wb;
string outFile;
public WebPageSnap(string url, string outputFile)
{
wb = new WebBrowser();
wb.ProgressChanged += wb_ProgressChanged;
outFile = outputFile;
wb.ScriptErrorsSuppressed = true;
wb.ScrollBarsEnabled = false;
wb.Navigate(url);
}
void wb_ProgressChanged(object sender, WebBrowserProgressChangedEventArgs e)
{
if (e.CurrentProgress == e.MaximumProgress)
{
wb.ProgressChanged -= wb_ProgressChanged;
try
{
int scrollWidth = 0;
int scrollHeight = 0;
scrollHeight = wb.Document.Body.ScrollRectangle.Height;
scrollWidth = wb.Document.Body.ScrollRectangle.Width;
wb.Size = new Size(scrollWidth, scrollHeight);
Bitmap bitmap = new Bitmap(wb.Width, wb.Height);
for (int Xcount = 0; Xcount < bitmap.Width; Xcount++)
for (int Ycount = 0; Ycount < bitmap.Height; Ycount++)
bitmap.SetPixel(Xcount, Ycount, Color.Black);
wb.DrawToBitmap(bitmap, new Rectangle(0, 0, wb.Width, wb.Height));
bitmap.Save(outFile, ImageFormat.Png);
}
catch { }
}
}
}