 |
 | Here is perfectly working C# code Madhava maydipalle | 5:05 19 Nov '09 |
|
 |
Thanks for all the people on this thread. here is working example..
Usage : To use from IE plugin :
SHDocVw.IWebBrowser2 browser = GetCurrentBrowser(); MHTHelper mhtHelper = new MHTHelper(); bool bMhtFile = mhtHelper.SaveAs(browser, filePath, EnumBrowserFileSaveType.SAVETYPE_ARCHIVE);
#region ---- EnumBrowserFileSaveType ---- public enum EnumBrowserFileSaveType { SAVETYPE_HTMLPAGE = 0, SAVETYPE_ARCHIVE, SAVETYPE_HTMLONLY, SAVETYPE_TXTONLY } #endregion
public class MHTHelper { #region ---- Constructor ---- public MHTHelper() { } #endregion #region ---- Private Attributes ---- private IWebBrowser2 webBrowser; private string filePath; private EnumBrowserFileSaveType saveType; private WindowHookProc HookProcedure; private int windowHook = 0; private IntPtr hwndSaveAsDlg = (IntPtr)0; private MHTHelper saveAsMht = null; #endregion #region ---- Public Attributes ---- public IWebBrowser2 WebBrowser { get { return webBrowser; } set { webBrowser = value; } }
public string FilePath { get { return filePath; } set { filePath = value; } } public EnumBrowserFileSaveType SaveType { get { return saveType; } set { saveType = value; } } #endregion #region ---- SaveAs ---- /// <summary> /// In this function we are automating the following functionality. /// 1.Select 'File->Save AS' menu item on IE /// 2.Take SaveAS dialog out of screen so that user cannot interact with it.(we cannot hide it, because of IE security policy.) /// 3.Set the required file path to the save as dialog. /// 4.Click on save button. /// 5.IE automatically display the status bar to show the extraction process of currently displayed web page into mht file. /// </summary> /// <param name="webBrowser"></param> /// <param name="pathFile"></param> /// <param name="saveType"></param> /// <returns></returns> public bool SaveAs(IWebBrowser2 webBrowser, string pathFile, EnumBrowserFileSaveType saveType) { try { this.WebBrowser = webBrowser; this.FilePath = pathFile; this.SaveType = saveType; //If no path is supplied or file already exists then it prompts for user action. if (0 == pathFile.Length) pathFile = "untitled"; if ((null == webBrowser) || (0 != windowHook)) return false; this.HookProcedure = new WindowHookProc(this.SaveAsHookProc); // prepare SaveAs dialog hook and activate it. this.windowHook = SetWindowsHookEx(5 /*WH_CBT*/, HookProcedure, (IntPtr)0, AppDomain.GetCurrentThreadId()); if (this.windowHook == 0) return false; try { // This following code shows the save as dialog this.saveAsMht = this; object o = null; webBrowser.ExecWB(SHDocVw.OLECMDID.OLECMDID_SAVEAS, SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_PROMPTUSER, ref o, ref o); this.saveAsMht = null; return true; } finally { //Here we took out our hook . UnhookWindowsHookEx(this.windowHook); this.windowHook =0; } } catch (Exception ex) { ExceptionHandler.Display(ex); return false; } }
#endregion #region ---- SaveAsHookProc ---- /// <summary> /// This proc is required to handle Window messages and do appropriate action for our requirements. /// </summary> /// <param name="nCode"></param> /// <param name="wParam"></param> /// <param name="lParam"></param> /// <returns></returns> public int SaveAsHookProc(int nCode, IntPtr wParam, IntPtr lParam) { switch (nCode) { case 3: // HCBT_CREATEWND CBT_CREATEWND cw = (CBT_CREATEWND)Marshal.PtrToStructure(lParam, typeof(CBT_CREATEWND)); CREATESTRUCT cs = (CREATESTRUCT)Marshal.PtrToStructure(cw.lpcs, typeof(CREATESTRUCT)); if (cs.lpszClass == 0x00008002) { this.hwndSaveAsDlg = (IntPtr)wParam; // Get hwnd of SaveAs dialog cs.x = -2 * cs.cx; // Move dialog off screen } break; case 5: // HCBT_ACTIVATE IntPtr hwnd = (IntPtr)wParam; //Here we get Save as dialog handle if (hwnd == this.hwndSaveAsDlg && this.hwndSaveAsDlg != (IntPtr)0) { //Prepare a thread to act as required messages source.Also set File path and its save type. ThreadPressOk tpok = new ThreadPressOk(hwnd, this.saveAsMht.FilePath, this.saveAsMht.SaveType); this.hwndSaveAsDlg = (IntPtr)0; // Create a thread to execute the task, and then // start the thread. new Thread((new ThreadStart(tpok.ThreadProc))).Start(); } break; } //This is required to pass control to next hook if exists on this process. return CallNextHookEx(this.windowHook, nCode, wParam, lParam); }
#endregion #region ---- Win32APIs ---- //Import for SetWindowsHookEx. [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)] public static extern int SetWindowsHookEx(int idHook, WindowHookProc lpfn, IntPtr hInstance, int threadId);
//Import for UnhookWindowsHookEx. [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)] public static extern bool UnhookWindowsHookEx(int idHook);
//Import for CallNextHookEx. //Use this function to pass the hook information to next hook procedure in chain. [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)] public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam); //This delegate is required to fetch our function to the thread. public delegate int WindowHookProc(int nCode, IntPtr wParam, IntPtr lParam);
//These Win32 structures are requred to handle windows messages/state [StructLayout(LayoutKind.Sequential)] public struct CBT_CREATEWND { public IntPtr lpcs; int hwndInsertAfter; }; [StructLayout(LayoutKind.Sequential)] public struct CREATESTRUCT { int lpCreateParams; int hInstance; int hMenu; int hwndParent; int cy; public int cx; int y; public int x; int style; int lpszName; public int lpszClass; int dwExStyle; } #endregion #region ---- Thread Requirements ---- //The following class is defined here because it is used in the above class only. //It sends all required thread messages to IE's save as dialog. class ThreadPressOk { public ThreadPressOk(IntPtr hwnd, string pathFile, EnumBrowserFileSaveType saveType) { this.hwndDialog = hwnd; this.pathFile = pathFile; this.saveType = saveType; }
IntPtr hwndDialog; string pathFile; EnumBrowserFileSaveType saveType;
// Imports of the User32 DLL. [DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)] public static extern IntPtr GetDlgItem(IntPtr hWnd, int nIDDlgItem);
[DllImport("user32.dll", CharSet = CharSet.Auto)] static extern private bool SetWindowText(IntPtr hWnd, string lpString); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool IsWindowVisible(IntPtr hWnd);
// The thread procedure performs the message loop and place the data public void ThreadProc() { //To avoid race condition, we are forcing this thread to wait until Saveas dialog is displayed. while (!IsWindowVisible(hwndDialog)) { Thread.Sleep(100); Application.DoEvents(); } Application.DoEvents(); //Get the handle to SaveType combo box on the save as dialog. IntPtr typeB = GetDlgItem(hwndDialog, 0x0470); //Get the handle to file path on the saveas dialog. IntPtr nameB = GetDlgItem(hwndDialog, 0x047c); //Get the handle to saveas on the saveas dialog. IntPtr saveBtn = GetDlgItem(hwndDialog, 0x0001); if (((IntPtr)0 != typeB) && ((IntPtr)0 != nameB) && ((IntPtr)0 != saveBtn) && IsWindowVisible(hwndDialog)) { //select save type SendMessage(typeB, 0x014E /*CB_SETCURSEL*/, (int)saveType, 0); SendMessage(hwndDialog, 0x0111 /*WM_COMMAND*/, 0x80470/*MAKEWPARAM(0x0470, CBN_CLOSEUP)*/, (int)typeB); // set save as filepath SetWindowText(nameB, pathFile); // Invoke Save button click. SendMessage(saveBtn, 0x00F5 /*BM_CLICK*/, 0, 0); } // Clean up GUI - we have clicked save button. //GC is going to do that cleanup job, so we are OK Application.DoEvents(); //Terminate the thread. return; } } #endregion }
Thanks Maydipalle
|
|
|
|
 |
 | Problem with code in Windows Vista and Windows 7 Nguyễn Đức Thiện | 19:29 24 Oct '09 |
|
 |
Hi to all, it been a long time since my last time I write/ask in the forum. I have the problem I hope you can help me: I’m using the guide: http://www.codeproject.com/KB/shell/iesaveas.aspx (Automated IE SaveAs MHTML) I have the problem when I’m running the code in Windows Vista In the method: void CSaveAsWebbrowser::UpdateSaveAs(HWND hwnd) { // editbox : filepath (control id = 0x047c) // dropdown combo : filetypes (options=complete page; // archive;html only;txt) (control id = 0x0470) // save button : control id = 0x0001 // cancel button : control id = 0x0002
// select right item in the combobox SendMessage(GetDlgItem(hwnd, 0x0470), CB_SETCURSEL, (WPARAM) m_nSaveType, 0); SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(0x0470,CBN_CLOSEUP), (LPARAM) GetDlgItem(hwnd, 0x0470));
// set output filename SetWindowText(GetDlgItem(hwnd, 0x047c), m_szFilename);
// Invoke Save button SendMessage(GetDlgItem(hwnd, 0x0001), BM_CLICK, 0, 0); } The problem is that we send the control id ‘0x047c’,(for the combo box and the output file), I noticed that the method GetDlgItem(hwnd, 0x047c), return 0, I’m thinking the problem is that the code id '0x047c' in Vista is not relevant, I found out that for NT, Windows 98 and 95 the combobox and output file has different ID ‘0x0480’, I was wandering I someone know where I can found the id’s for Vista, or someone have another idea why this is not working. Thanks
|
|
|
|
 |
 | This can't run on windows 7 Nguyễn Đức Thiện | 7:09 24 Oct '09 |
|
 |
Hello! I use this code to run success on Windows Xp (whith IE8) but can't exact on Windows 7 (with IE8). Help me!
|
|
|
|
 |
 | Do you know what would be the libraries use for C# ? Battosaiii | 7:31 10 Aug '09 |
|
 |
I would like to use custom dialog to save as webpages from internet explorer. It would be done in C#. Do you know the libraries for C# ? I have been looking for libraries in c# but i cant find anything !
|
|
|
|
 |
 | Pages with big sizes are not being able to saved in IE explorer itself HMLGUY | 22:19 28 Jun '09 |
|
 |
Hi
I am using your application for programmatically saving file from IE Automated IE SaveAs MHTML Well only one small change I have made. In your application 1)You create a separate browser control 2)Navigate it to web page 3)And then Save the file using HRESULT hr = m_pWebBrowser->ExecWB(cmdid, OLECMDEXECOPT_PROMPTUSER, NULL, NULL);
I have included SaveAsThread.cpp and SaveAsWebBrowser.cpp in my application. Only change I have made is in your SetWebBrowser method, Instead of setting your application's browser control, I get an instance of currently running IE(IE version 8) and set it in SetWebBrowser method Then I have added one button on IE toolbar and on click of it I call m_wbSaveAs.Config( CString(finalFilePath), SAVETYPE_ARCHIVE ); m_wbSaveAs.SaveAs()
where finalFilePath is path of file to be saved
Now when ever I surf lighter pages or pages with small size, I am able to Save pages and your program runs amazing. But when ever i surf heavy pages for example home page of http://indiatimes.com my instance of IE gets hanged and page is not being able to saved.
Same heavy page when I surf in your application and in your web browser control instead of IE itself, application works absolutely fine and is able to save page. Do you have any idea, why IE itself is not able to perform the same.
Any clues or help would be of great help
Thanks in advance
|
|
|
|
 |
 | Can we use SetWindowsHookEx for hooking printer dialogs? Member 3728841 | 18:18 10 Dec '08 |
|
 |
hi
Can we in any way use SetWindowsHookEx in hooking printer dialogs using printHookProc()??plz tell me otherwise how to do so?if somebody can explain giving sample code that will be more helpful to me as i'm a newbie in this.. thanks and regards Rm
|
|
|
|
 |
 | can you use the hook for retriveing the address bar content? rerb | 10:47 26 Jul '07 |
|
 |
Is this possible? I am also a VB.net user but any info or sample would be very helpfull. thanks
|
|
|
|
 |
 | Excellent! Can this be done in VB.Net? saab340b | 7:36 6 Apr '07 |
|
 |
I have spend days looking for this information. Now that I've finally found it, it is NOT in vb.net. Ever thought of converting it?
|
|
|
|
 |
 | How can I save HTML from IE kallol kumar | 1:47 1 Aug '06 |
|
 |
Hello, cool...Its a nice work.I have a problem of saving HTML.I developed a project which is load url into Internet Explorer(shell Executing iexplore.exe). But I cann't save that Url automatically. I want to save it without showing its saveAs Dialog.I am trying it with your project. But I cann't. Can you please give me any ideas.
Thanks Kallol
|
|
|
|
 |
 | Save as xls file xgnitesh | 1:15 15 Feb '06 |
|
 |
Hi, First of all I would like to thank the author for the excellent article. This works perfectly for HTML pages. Now I have a requirement where the URL link may point to a excel file or a pdf file or any other kind of binay file. When I use the program for excel file, the save as dialog box does popup but the BM_CLICK message does not work to invoke the save button. I noticed that this is because there is another kind of save as dialog that appears when we try to save the excel file (different from the one that appears when you try to do save as for HTML pages). I thought that the resource id for save button must have changed and tried 1 to 100 all ids not just 1. But no success. Then I tried to use Spy++ drag and drop feature to identify the save button window, but unfortunately even Spy++ does not identify this save button as an independent window.
Possible questions: How can I indentify the right button resource id? How can invoke the save button in this new kind of save as dialog?
Any help is appreciated.
Thanks & regards, Nitesh
|
|
|
|
 |
 | How to know whether a printer is connected or not vijay kumar T | 8:50 17 Jan '06 |
|
 |
I have a problem with the printer. I want to know whether a printer is physically connected and then I want to issue a print command. If any one can help me I would be greatful.
|
|
|
|
 |
|
 |
What has this to do with the article?
|
|
|
|
 |
|
 |
Ofcourse it is not related but some one working with printers may respond.
|
|
|
|
 |
 | Problem in Release version Roland Liu | 18:09 15 Jan '06 |
|
 |
Your code is very good in debug version, but in release version, I can't save any .mhtml file. This is a big bug, I hope you find why the Problem occur only in Release version.
Zjroland from http://www.outsourcexp.com
|
|
|
|
 |
 | How to save web page silently just from the url? Tcpip2005 | 18:21 6 May '05 |
|
 |
I mean how to save a web page without navigate to the page just from the url ? also the save as dialog box should not be shown.
Thank you sir
|
|
|
|
 |
 | desktop flickering problem and realese problem Libi1234 | 21:33 19 Mar '05 |
|
 |
Hi, I used your code in order to save several pages in a loop. The problem acuur, while its in prosses. The desktop is flickering, assume when the hidden dialog being closed. Have someone an idea how to resolve it?
--UPDATE--
In realese mode there is a problem in varibal m_bUpdateUI that somehow is always false!!! Some idea??
thanks. Great and Excellent job!
|
|
|
|
 |
|
 |
http://www.codeproject.com/shell/iesaveas.asp?msg=483194#xx483194xx
|
|
|
|
 |
|
 |
Thanks. What about the flickering prob?
|
|
|
|
 |
 | Help to without prompt dialogbox to user baskarchinnu | 0:21 28 Feb '05 |
|
 |
Hi I am working in Win32 API SDK, at my program, I am hooking IE window and I am using my own BHO dll (whenever IE is open, dll will attach with IE browser) through this dll I want to save the complete web page without prompting the save as dialogbox. With your example help, I tried by using as follows
HRESULT hr = m_pWebBrowser->ExecWB(OLECMDID_SAVEAS, MSOCMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
I used MSOCMDEXECOPT_DONTPROMPTUSER options, even though I am getting dialog box and even if try to save the web page through save as dialog box also, page is not saving. I am getting the error msg "This Web page could not be saved".
Can you please help me to save the complete web page without prompting save..as dialog box.
Thanks in Advance
Baskar
|
|
|
|
 |
 | Save the modified page Berkeley Wong | 8:15 20 Nov '04 |
|
 |
How can I save the modified HTML page to local using C++?
|
|
|
|
 |
|
 |
You have to switch IE in edit mode first. There are numerous articles available out there (even a few on codeproject if I remember well).
|
|
|
|
 |
|
 |
I need to modify the HTML form's value (say one entry field Name) and then save this HTML page with the given name to the local machine. I tried to use this example to save the HTML page to local, it is OK , but the page does not contain modified value (name) in the entry field. Could you explain more and any alternative to do this in C++?
|
|
|
|
 |
|
 |
Did you (anyone?) ever find a solution how to save the modified html page to mht? I would be interested to know.
Regards, Fredrik
|
|
|
|
 |
 | win98 NorrieTaylor | 21:02 29 Aug '04 |
|
 |
I can't get this to work with Win98 even if use the tip mentioned in the previous thread. It seems to hang before it even gets to that point. If anyone can help I would greatly appreciate it.
Best regards,
Norrie Taylor
|
|
|
|
 |
 | Win98 Different DialogID TDK900000 | 6:16 10 May '04 |
|
 |
Great article but it fails for me using IE6 on Win98. I think the reason is that the dialog IDS are different. For example GetDlgItem(hwnd, 0x47c) returns NULL for me in UpdateSaveAs.
Does anyone know either 1. What the correct dialog IDS for win 98 2. Which dll the resource is in so I can try to find out the dialog ID 3. A way around this problem.
Cheers
|
|
|
|
 |