<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Rob&#039;s Notebook</title>
	<atom:link href="https://robsnotebook.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://robsnotebook.com</link>
	<description></description>
	<lastBuildDate>Sun, 20 Sep 2020 15:54:13 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
<site xmlns="com-wordpress:feed-additions:1">182480498</site>	<item>
		<title>Batch script for opening an application at desired window position from command line</title>
		<link>https://robsnotebook.com/batch-to-launch-an-application-at-desired-window-position-from-command-line/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=batch-to-launch-an-application-at-desired-window-position-from-command-line</link>
		
		<dc:creator><![CDATA[Rob]]></dc:creator>
		<pubDate>Sun, 20 Sep 2020 14:57:34 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[batch]]></category>
		<category><![CDATA[MoveWindow]]></category>
		<category><![CDATA[powershell]]></category>
		<guid isPermaLink="false">https://robsnotebook.com/?p=90</guid>

					<description><![CDATA[I recently had the need to launch/open multiple instances of the same windows application at different window positions. The web provided various solutions, but there wasn&#8217;t any single tidy batch script that tied everything together. My desire was to have a single batch script where I could specify the position, application, and all the application&#8217;s [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>I recently had the need to launch/open multiple instances of the same windows application at different window positions. The web provided various solutions, but there wasn&#8217;t any single tidy batch script that tied everything together. My desire was to have a single batch script where I could specify the position, application, and all the application&#8217;s arguments in one command line.</p>



<p>This is accomplished with the &#8220;launchnmove.bat&#8221; batch script which is shown below.</p>



<p>You invoke it with:</p>



<blockquote class="is-layout-flow wp-block-quote-is-layout-flow">
<pre>launchnmove.bat &lt;xposition&gt; &lt;yposition&gt; &lt;program name&gt; [arg1] [arg2] ...
</pre>
</blockquote>



<p>&lt;xposition&gt; is the desired new upper left position of the window<br />&lt;yposition&gt; is the desired top right position of the window<br />&lt;program name&gt; is the application you desire to launch<br />[arg1] [arg2] &#8230; corresponds to the arguments to your application.</p>



<p>See the example below of another batch file where 2 different notepad applications are launched at 2 different window positions:</p>



<blockquote class="is-layout-flow wp-block-quote-is-layout-flow">
<pre>call launchnmove.bat 0 0 notepad.exe doc1.txt
call launchnmove.bat 300 50 notepad.exe doc2.txt
</pre>
</blockquote>



<p>Above example assumes &#8220;launchnmove.bat&#8221; is in your PATH, but you could update the example to provide the full path to launchnmove.bat.</p>



<p>You can use launchnmove.bat inside of other batch scripts to open the same, or different windows applications at desired positions. For usage inside of other batch scripts make sure to use &#8220;call&#8221; such as &#8220;call launchnmove.bat &#8230;&#8221;.</p>



<p>Here are the contents of launchnmove.bat so that you may copy/paste and use it:</p>



<blockquote>
<pre>&lt;# :
:: Based on https://gist.github.com/coldnebo/1148334
:: Converted to a batch/powershell hybrid via http://www.dostips.com/forum/viewtopic.php?p=37780#p37780
@echo off
setlocal
set "POWERSHELL_BAT_ARGS=%*"
if defined POWERSHELL_BAT_ARGS set "POWERSHELL_BAT_ARGS=%POWERSHELL_BAT_ARGS:"=\"%"
endlocal &amp; powershell -NoLogo -NoProfile -Command "$_ = $input; Invoke-Expression $( '$input = $_; $_ = \"\"; $args = @( &amp;{ $args } %POWERSHELL_BAT_ARGS% );' + [String]::Join( [char]10, $( Get-Content \"%~f0\" ) ) )"
goto :EOF
#&gt;

Add-Type @"
  using System;
  using System.Runtime.InteropServices;

  public class Win32 {
    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
  }

  public struct RECT
  {
    public int Left;        // x position of upper-left corner
    public int Top;         // y position of upper-left corner
    public int Right;       // x position of lower-right corner
    public int Bottom;      // y position of lower-right corner
  }
"@

$progname = $args[2]
$progargs = $args[3..($args.Count-1)]
#Write-Host "progargs=$progargs"
$rcWindow = New-Object RECT
$MyProcess = Start-Process -FilePath $progname -ArgumentList $progargs -PassThru

While ($MyProcess.MainWindowHandle -eq 0) {
Start-Sleep -Seconds 1
}

$h = $MyProcess.MainWindowHandle

# Set GetWindowRect output = to $ret so that it doesn't print 'True' to the terminal
$ret = [Win32]::GetWindowRect($h,[ref]$rcWindow)

$win_width = $rcWindow.Right - $rcWindow.Left
$win_height = $rcWindow.Bottom - $rcWindow.Top
$screen_x=$args[0]
$screen_y=$args[1]

# Set MoveWindow output = to $ret so that it doesn't print 'True' to the terminal
$ret = [Win32]::MoveWindow($h, $screen_x, $screen_y, $win_width, $win_height, $true )
</pre>
</blockquote>



<p>&nbsp;</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">90</post-id>	</item>
		<item>
		<title>Check cygwin not in use before updating</title>
		<link>https://robsnotebook.com/check-cygwin-not-in-use-before-updating/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=check-cygwin-not-in-use-before-updating</link>
		
		<dc:creator><![CDATA[Rob]]></dc:creator>
		<pubDate>Mon, 07 Sep 2020 17:25:40 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[cygwin]]></category>
		<category><![CDATA[cygwin dll in use]]></category>
		<category><![CDATA[unlocker]]></category>
		<category><![CDATA[update cygwin]]></category>
		<guid isPermaLink="false">https://robsnotebook.com/?p=84</guid>

					<description><![CDATA[Periodically I like to update cygwin, add a new package or update an existing package. One annoying thing about updating cygwin is that if any cygwin files are in use (such as one of its dll files) when you perform the update the setup will complain it can&#8217;t overwrite the dll and tell you that [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Periodically I like to update cygwin, add a new package or update an existing package. One annoying thing about updating cygwin is that if any cygwin files are in use (such as one of its dll files) when you perform the update the setup will complain it can&#8217;t overwrite the dll and tell you that you will need to reboot after the installation is over. This often happens to me because I have an ssh server and X server running. Before updating cygwin I need to stop those. It may also be possible that I&#8217;m still running an ssh-agent or some other process.</p>



<p>I have found that it is possible to figure out ahead of time if any of the cygwin dll files are in use.</p>



<p>The trick is to use the excellent &#8220;<a href="http://www.emptyloop.com/unlocker/">unlocker</a>&#8221; (or similar) utility. The primary purpose of <a href="http://www.emptyloop.com/unlocker/">unlocker</a> is to let you know why you can&#8217;t delete a file, which process is locking it. You can use this information to see which processes and still using cygwin, and then you can decide how to terminate them. </p>



<p>For example, if your ssh server is still running you can do &#8220;net stop cygsshd&#8221; in an admin prompt. To stop the syslogger do: &#8220;net stop syslog-ng&#8221;</p>



<p>After you have unlocker installed, when it is time to update cygwin first use Windows Explorer to navigate to directory</p>



<p>c:\cygwin64\bin</p>



<p>Look for:</p>



<p>cygwin1.dll</p>



<p>Right click on &#8220;cygwin1.dll&#8221; and choose &#8220;unlocker&#8221;. Windows may prompt you for admin roots so approve that.</p>



<p>Then you will get a window showing all the processes that are using cygwin. I recommend trying to shut them all down the &#8220;normal&#8221; way, exit bash shells, stop your ssh server, stop your &#8220;X server&#8221; by right clicking in the system tray and exiting. If you can&#8217;t figure out a graceful way to exit then you can use unlocker to kill those processes.</p>



<p>Once unlocker shows that no more processes are using cygwin then you can proceed with an install knowing that nothing will be locked and you won&#8217;t need to reboot after the installation.</p>



<p>After the install/update is done you&#8217;ll want to restart things like:</p>



<p>net start syslog-ng<br>net start cygsshd</p>



<p></p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">84</post-id>	</item>
		<item>
		<title>Symbolic Links in Windows with Unison</title>
		<link>https://robsnotebook.com/symbolic-links-in-windows-with-unison/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=symbolic-links-in-windows-with-unison</link>
		
		<dc:creator><![CDATA[Rob]]></dc:creator>
		<pubDate>Mon, 07 Sep 2020 16:38:05 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[cygwin]]></category>
		<category><![CDATA[symbolic links]]></category>
		<category><![CDATA[symbolic links windows]]></category>
		<category><![CDATA[symbolic links windows unison]]></category>
		<category><![CDATA[symlinks windows]]></category>
		<category><![CDATA[symlinks windows unison]]></category>
		<category><![CDATA[unison]]></category>
		<guid isPermaLink="false">https://robsnotebook.com/?p=76</guid>

					<description><![CDATA[It is possible to use unison on windows and synchronize symbolic links with remote systems and keep these symbolic links as actual links and not &#8220;follow&#8221; or copy the files. The windows version of Unison does not support syncing symbolic links as actual links, but there is a way to get symlinks supported. The trick [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>It is possible to use <a href="https://www.cis.upenn.edu/~bcpierce/unison/">unison</a> on windows and synchronize symbolic links with remote systems and keep these symbolic links as actual links and not &#8220;follow&#8221; or copy the files. The windows version of Unison does not support syncing symbolic links as actual links, but there is a way to get symlinks supported.</p>



<p>The trick to getting symbolic links to work is to use the cygwin version of unison. When you install cygwin using the cygwin setup program, there are options to install various different versions of unison compiled for cygwin. By using cygwin, unison thinks it is running in a Posix environment which does support symbolic links, cygwin unison does not realize that it is actually running in Windows.</p>



<p>There may be some limitations such as if you have remote drives attached then windows itself may not support symbolic links. However your local NTFS file systems can and do support symbolic links.</p>



<p>In order to enable symbolic link support in cygwin and Windows, there are a few extra steps you need to take before you start syncing.</p>



<h2 class="wp-block-heading">Configurate cygwin to have &#8216;exec&#8217; file rights and handle permissions with &#8216;noacl&#8217;</h2>



<p>This step is optional, you&#8217;ll be able to sync with symlinks without using &#8216;exec&#8217; and &#8216;noacl&#8217;. But syncing will be slower without &#8216;exec&#8217;, and there may be permissions issues without &#8216;noacl&#8217;.</p>



<p>unison is interested in syncing file permissions. If a file is not obviously executable (like having .exe extension), by default cygwin checks for &#8220;exec&#8221; permission by opening a file and looking for the &#8220;hashbang&#8221; or &#8220;#!&#8221;. This can slow down syncing significantly. You can tell cygwin to think each file is executable by assigning &#8220;exec&#8221; to mounted file systems in the &#8220;/etc/fstab&#8221; file.</p>



<p>I also find that it is useful to setup the &#8220;noacl&#8221; property in /etc/fstab, otherwise I don&#8217;t see permissions synced properly.</p>



<p>Take note that there is already an existing entry in your /etc/fstab without &#8220;exec&#8221; or &#8220;noacl&#8221;. You&#8217;ll either want to delete it or comment it out with a # character at the start of the line. Also note that if you keep your home directory in the standard &#8220;/home&#8221; in cygwin, you&#8217;ll need to add an entry for /home. You can modify the entiry for /home if you want your home directory outside of the &#8220;c:/cygwin64&#8221; directory.</p>



<p>My /etc/fstab file looks like the following:</p>



<pre class="wp-block-code"><code># See http://old.nabble.com/vim-and-file-permissions-on-Windows-7-td29162830.html
# and http://stackoverflow.com/questions/5828037/cygwin-sets-file-permission-to-000
# Using "exec" flag to make cygwin faster and not open each file to check for hashbang
# to see if it is executable. On windows all files are executable anyway.
# Using "noacl" for better handling of file permissions
none /cygdrive cygdrive binary,exec,noacl,posix=0,user 0 0
c:/cygwin64/home /home home binary,exec,noacl,posix=0,user 0 0</code></pre>



<p>You will need to reboot your PC after making this change for it to take effect, however the next step (give rights to create symbolic links) also involves a reboot so you can perform the next step and have its reboot be the 1 reboot for this step and the next one.</p>



<p>You can check if the settings of fstab took place by running at cygwin prompt the &#8220;mount&#8221; command, which will show you the options for the /cygdrive and /home mounts.</p>



<h2 class="wp-block-heading">Give your user the rights to create symbolic links</h2>



<p>Before syncing symlinks with windows, you need to give your user the rights to create symbolic links. By default, Windows requires admin rights to create symlinks. You can enable this by:</p>



<ul class="wp-block-list"><li>Start a cygwin prompt as Administrator<ul><li>Start-&gt;Cygwin</li><li>Right click on Cygwin64 terminal</li><li>select &#8220;more&#8221;</li><li>left click on &#8220;Run as administrator&#8221;</li></ul></li><li>Type and run the &#8220;editrights&#8221; command as below<ul><li>editrights -u $(whoami) -a SeCreateSymbolicLinkPrivilege</li></ul></li><li>Check that you actually have the &#8220;SeCreateSymbolicLinkPrivilege&#8221; right<ul><li> editrights -l -u $(whoami)</li><li>You should in the output:  &#8220;SeCreateSymbolicLinkPrivilege&#8221;</li></ul></li><li>For this right to take effect you need to sign out/sign back in or restart windows</li></ul>



<h2 class="wp-block-heading">Set CYGWIN variable to enable native symbolic link support</h2>



<p>cygwin by default uses symbolic links that only cygwin programs understand. If you want native windows programs that do not use cygwin to also &#8220;see&#8221; the symbolic links, you need to set the CYGWIN environment variable properly. I prefer using &#8220;winsymlinks:native&#8221; and not &#8220;winsymlinks:nativestrict&#8221; because there may be some cases where you are syncing symlinks that don&#8217;t point to existing targets so in those cases cygwin will use the cygwin symlink to at least have a link, whereas native symlinks do not support pointing to non-existing targets.</p>



<p>To enable CYGWIN support of symbolic links for when you launch a cygwin shell from your desktop:</p>



<ul class="wp-block-list"><li>Click &#8220;Start&#8221; in windows</li><li>Start typing &#8220;Edit the system environment variables&#8221;</li><li>Click &#8220;Edit the system environment variables&#8221;</li><li>In the &#8220;System properties&#8221; (or &#8220;user properties&#8221; if you just want it for your user), check if CYGWIN is already defined.<ul><li>If not defined, click &#8220;New&#8221;<ul><li>Variable name: CYGWIN</li><li>Variable value: &#8220;winsymlinks:native&#8221;</li></ul></li><li>If already defined, edit the CYGWIN variable and add &#8220;winsymlinks:native&#8221;</li></ul></li></ul>



<pre id="block-de351d28-22bb-49ee-b497-ed9f92ab3501" class="wp-block-preformatted"></pre>



<h2 class="wp-block-heading">ssh server setup to handle symbolic links</h2>



<p>If you have previously setup an ssh server, you may have not configured it to set the CYGWIN environment variable to properly handle symbolic links. To change your ssh server&#8217;s CYGWIN, you&#8217;ll need to uninstall and re-install your cygwin ssh server.</p>



<ul class="wp-block-list"><li>Before proceeding, make a backup of your /etc/sshd_config file</li><li>Start a cygwin prompt as administrator</li><li>Stop your existing ssh server from running<ul><li>net stop cygsshd</li></ul></li><li>Delete the service<ul><li>cygrunsrv &#8211;remove cygsshd</li></ul></li><li>Rerun ssh-host-config, tell it to overwrite the existing /etc/sshd_config file and then when it asks for the CYGWIN environment variable setting specify &#8220;winsymlinks:native&#8221;. A log of how I have done this is shown below</li></ul>



<p><code>*** Info: Generating missing SSH host keys</code><br><code>*** Query: Overwrite existing&nbsp;/etc/ssh_configfile? (yes/no) no</code><br><code>*** Query: Overwrite existing&nbsp;/etc/sshd_configfile? (yes/no)&nbsp;yes</code><br><code>*** Info: Creating default&nbsp;/etc/sshd_configfile</code><br><br><code>*** Info: StrictModes is&nbsp;setto&nbsp;'yes'by default.</code><br><code>*** Info: This is the recommended setting, but it requires that the POSIX</code><br><code>*** Info: permissions of the user's home directory, the user's .ssh</code><br><code>*** Info: directory, and the user's&nbsp;sshkey files are tight so that</code><br><code>*** Info: only the user has write permissions.</code><br><code>*** Info: On the other hand, StrictModes don't work well with default</code><br><code>*** Info: Windows permissions of a home directory mounted with the</code><br><code>*** Info:&nbsp;'noacl'option, and they don't work at all&nbsp;ifthe home</code><br><code>*** Info: directory is on a FAT or FAT32 partition.</code><br><code>*** Query: Should StrictModes be used? (yes/no) no</code><br><code>*** Info: Updating&nbsp;/etc/sshd_configfile</code><br><br><code>*** Query: Do you want to&nbsp;installsshd as a service?</code><br><code>*** Query: (Say&nbsp;"no"ifit is already installed as a service) (yes/no)&nbsp;yes</code><br><code>*** Query: Enter the value of CYGWIN&nbsp;forthe daemon: [] winsymlinks:native</code><br><br><code>*** Info: The sshd service has been installed under the LocalSystem</code><br><code>*** Info: account (also known as SYSTEM). To start the service now, call</code><br><code>*** Info: `net start cygsshd' or `cygrunsrv -S cygsshd'.&nbsp; Otherwise, it</code><br><code>*** Info: will start automatically after the next reboot.</code><br><code>*** Info: Host configuration finished. Have fun!</code></p>



<ul class="wp-block-list"><li>Edit your new /etc/sshd_config and restore any settings you had there</li><li>Restart the ssh server<ul><li>net start cygsshd</li></ul></li><li>Test that you can ssh into your machine</li><li>Once you are in an ssh session, do &#8220;echo $CYGWIN&#8221; and check that the &#8220;winsymlinks:native&#8221; property is in the CYGWIN environment variable</li></ul>



<h2 class="wp-block-heading">Happy syncing with symlinks</h2>



<p>That&#8217;s it. Now when you perform syncs, from either a linux or windows machine that has symbolic links, these symbolic links should get preserved. With the &#8220;exec&#8221; setting of your /etc/fstab, the syncs should be faster.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">76</post-id>	</item>
		<item>
		<title>Copy an Excel Sheet to a Different Workbook using Apache POI</title>
		<link>https://robsnotebook.com/copy-a-sheet-to-a-different-workbook-in-apache-poi/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=copy-a-sheet-to-a-different-workbook-in-apache-poi</link>
		
		<dc:creator><![CDATA[Rob]]></dc:creator>
		<pubDate>Wed, 01 Jan 2020 21:56:02 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://robsnotebook.com/?p=73</guid>

					<description><![CDATA[I recently wanted to copy an Excel worksheet using Apache POI from one workbook to another workbook. I desired to have this copy include all styles, such as bold/underline/etc, preserve all merged cells, and preserve all Sheet properties. Various StackOverflow posts pointed to this thread on coderanch. I found the code there to be broken [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I recently wanted to copy an Excel worksheet using Apache POI from one workbook to another workbook. I desired to have this copy include all styles, such as bold/underline/etc, preserve all merged cells, and preserve all Sheet properties.</p>
<p>Various StackOverflow posts pointed to <a href="https://coderanch.com/t/420958/open-source/Copying-sheet-excel-file-excel"> this thread on coderanch</a>. I found the code there to be broken into many different pieces, as well as having a handful of bugs and also using many deprecated (or not existing anymore) functions in Apache POI 4.1.1.</p>
<p>After fixing the bugs that impacted my use case, as well as quite a bit of refactoring for better readability and convenience, I have working java code for both XSSF and HSSF formats.</p>
<p>Below is an example of how to use this new code:</p>
<blockquote>
<pre>// Get your sourceSheet object, your code may be different
Sheet sourceSheet = sourceWorkbook.getSheetAt(0);

// Create your destination sheet object, you may have a different sheet name
Sheet destinationSheet = destinationWorkbook.createSheet("New Sheet Name");

// Perform the copy using PoiCopySheet.copySheet()
PoiCopySheet.copySheet(sourceSheet, destinationSheet);
</pre>
</blockquote>
<p>Caveats: There are 2 things left out from the coderanch thread. The below code does not copy pictures to the new Sheet, nor does it copy print titles. Those could be added if you merge in the code from the coderanch post, but I didn&#8217;t take the time to do it.</p>
<p>Below is the java code to perform the Sheet copy using Apache POI 4.1.1 and Java 11:</p>
<blockquote>
<pre>import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;

public class PoiCopySheet
{
    private Set&lt;CellRangeAddressWrapper&gt; mergedRegions_ = new TreeSet&lt;CellRangeAddressWrapper&gt;();
    private Sheet srcSheet_;
    private Sheet dstSheet_;
    private Workbook srcWorkbook_;
    private Workbook dstWorkbook_;
    private CellStyle[] srcToDstStyle_;

    private PoiCopySheet(Sheet srcSheet, Sheet dstSheet)
    {
        srcSheet_ = srcSheet;
        dstSheet_ = dstSheet;
        srcWorkbook_ = srcSheet.getWorkbook();
        dstWorkbook_ = dstSheet.getWorkbook();
    }

    public static void copySheet(Sheet srcSheet, Sheet dstSheet)
    {
        PoiCopySheet poiCopySheet = new PoiCopySheet(srcSheet, dstSheet);
        poiCopySheet.copySheetInst();
    }

    private CellStyle getDstStyleFromSrcStyle(CellStyle srcStyle)
    {
        return srcToDstStyle_[srcStyle.getIndex()];
    }

    private void copySheetInst()
    {
        mapCellStyles();
        copySheetSettings();
        int maxColumnNum = 0;
        for (int i = srcSheet_.getFirstRowNum(); i &lt;= srcSheet_.getLastRowNum(); i++)
        {
            Row srcRow = srcSheet_.getRow(i);
            Row destRow = dstSheet_.createRow(i);
            if (srcRow != null)
            {
                copyRow(srcRow, destRow);
                if (srcRow.getLastCellNum() &gt; maxColumnNum)
                {
                    maxColumnNum = srcRow.getLastCellNum();
                }
            }
        }
        for (int i = 0; i &lt;= maxColumnNum; i++)
        {
            dstSheet_.setColumnWidth(i, srcSheet_.getColumnWidth(i));
            CellStyle srcColStyle = srcSheet_.getColumnStyle(i);
            if (srcColStyle != null)
            {
                dstSheet_.setDefaultColumnStyle(i, getDstStyleFromSrcStyle(srcColStyle));
            }
        }
    }

    private void mapCellStyles()
    {
        int totalSrcCellStyles = srcWorkbook_.getNumCellStyles();
        srcToDstStyle_ = new CellStyle[totalSrcCellStyles];
        for (int srcStyleIdx = 0; srcStyleIdx &lt; totalSrcCellStyles; ++srcStyleIdx)
        {
            CellStyle srcCellStyle = srcWorkbook_.getCellStyleAt(srcStyleIdx);
            srcToDstStyle_[srcStyleIdx] = getCellStyle(srcCellStyle);
        }
    }

    private void copyRow(Row srcRow,
                         Row dstRow)
    {
        if (srcRow.isFormatted())
        {
            CellStyle srcRowStyle = srcRow.getRowStyle();
            CellStyle dstRowStyle = getDstStyleFromSrcStyle(srcRowStyle);
            dstRow.setRowStyle(dstRowStyle);
        }

        short dh = srcSheet_.getDefaultRowHeight();
        if (srcRow.getHeight() != dh)
        {
            dstRow.setHeight(srcRow.getHeight());
        }

        int j = srcRow.getFirstCellNum();
        if (j &lt; 0)
        {
            j = 0;
        }
        for (; j &lt;= srcRow.getLastCellNum(); j++)
        {
            Cell srcCell = srcRow.getCell(j); // ancienne cell
            Cell dstCell = dstRow.getCell(j); // new cell
            if (srcCell != null)
            {
                if (dstCell == null)
                {
                    dstCell = dstRow.createCell(j);
                }

                copyCell(srcCell, dstCell);
                CellRangeAddress mergedRegion = getMergedRegion(srcSheet_, srcRow.getRowNum(),
                                                                (short)srcCell.getColumnIndex());

                if (mergedRegion != null)
                {
                    CellRangeAddress dstMergedRegion = new CellRangeAddress(mergedRegion.getFirstRow(),
                                                                            mergedRegion.getLastRow(), mergedRegion.getFirstColumn(), mergedRegion.getLastColumn());
                    CellRangeAddressWrapper wrapper = new CellRangeAddressWrapper(dstMergedRegion);
                    if (isdstMergedRegion(wrapper))
                    {
                        mergedRegions_.add(wrapper);
                        dstSheet_.addMergedRegion(wrapper.range);
                    }
                }
            }
        }
    }

    private static CellRangeAddress getMergedRegion(Sheet sheet, int rowNum, short cellNum)
    {
        for (int i = 0; i &lt; sheet.getNumMergedRegions(); i++)
        {
            CellRangeAddress merged = sheet.getMergedRegion(i);
            if (merged.isInRange(rowNum, cellNum))
            {
                return merged;
            }
        }
        return null;
    }

    private boolean isdstMergedRegion(CellRangeAddressWrapper dstMergedRegion)
    {
        return !mergedRegions_.contains(dstMergedRegion);
    }

    private void copyCell(Cell srcCell, Cell dstCell)
    {
        if (srcWorkbook_ == dstWorkbook_)
        {
            dstCell.setCellStyle(srcCell.getCellStyle());
        }
        else
        {
            CellStyle dstCellStyle = getDstStyleFromSrcStyle(srcCell.getCellStyle());
            dstCell.setCellStyle(dstCellStyle);
        }
        switch (srcCell.getCellType())
        {
        case STRING:
            dstCell.setCellValue(srcCell.getStringCellValue());
            break;
        case NUMERIC:
            dstCell.setCellValue(srcCell.getNumericCellValue());
            break;
        case BLANK:
            dstCell.setBlank();
            break;
        case BOOLEAN:
            dstCell.setCellValue(srcCell.getBooleanCellValue());
            break;
        case ERROR:
            dstCell.setCellErrorValue(srcCell.getErrorCellValue());
            break;
        case FORMULA:
            dstCell.setCellFormula(srcCell.getCellFormula());
            break;
        default:
            break;
        }
    }

    private CellStyle getSameCellStyle(CellStyle srcCellStyle)
    {
        DataFormat dstDataFormat = dstWorkbook_.createDataFormat();
        String srcDataFormatString = srcCellStyle.getDataFormatString();
        short expectedSrcDataFormat = dstDataFormat.getFormat(srcDataFormatString);

        int totalSrcCellStyles = dstWorkbook_.getNumCellStyles();
        for (int dstStyleIdx = 0; dstStyleIdx &lt; totalSrcCellStyles; ++dstStyleIdx)
        {
            CellStyle currentCellStyle = dstWorkbook_.getCellStyleAt(dstStyleIdx);

            if (cellStylesEquals(currentCellStyle,      // CellStyle leftStyle,
                                 dstWorkbook_,          // Workbook leftWorkbook,
                                 srcCellStyle,          // CellStyle rightStyle,
                                 srcWorkbook_,          // Workbook rightWorkbook,
                                 expectedSrcDataFormat) // short rightDataFormat,
            )
            {
                return currentCellStyle;
            }
        }
        return null;
    }

    private static boolean cellStylesEquals(CellStyle leftStyle,
                                            Workbook leftWorkbook,
                                            CellStyle rightStyle,
                                            Workbook rightWorkbook,
                                            short rightDataFormat)
    {
        if (leftStyle.getAlignment() != rightStyle.getAlignment())
        {
            return false;
        }
        if (leftStyle.getHidden() != rightStyle.getHidden())
        {
            return false;
        }
        if (leftStyle.getLocked() != rightStyle.getLocked())
        {
            return false;
        }
        if (leftStyle.getWrapText() != rightStyle.getWrapText())
        {
            return false;
        }
        if (leftStyle.getBorderBottom() != rightStyle.getBorderBottom())
        {
            return false;
        }
        if (leftStyle.getBorderLeft() != rightStyle.getBorderLeft())
        {
            return false;
        }
        if (leftStyle.getBorderRight() != rightStyle.getBorderRight())
        {
            return false;
        }
        if (leftStyle.getBorderTop() != rightStyle.getBorderTop())
        {
            return false;
        }
        if (leftStyle.getBottomBorderColor() != rightStyle.getBottomBorderColor())
        {
            return false;
        }
        if (leftStyle.getFillBackgroundColor() != rightStyle.getFillBackgroundColor())
        {
            return false;
        }
        if (leftStyle.getFillForegroundColor() != rightStyle.getFillForegroundColor())
        {
            return false;
        }
        if (leftStyle.getFillPattern() != rightStyle.getFillPattern())
        {
            return false;
        }
        if (leftStyle.getIndention() != rightStyle.getIndention())
        {
            return false;
        }
        if (leftStyle.getLeftBorderColor() != rightStyle.getLeftBorderColor())
        {
            return false;
        }
        if (leftStyle.getRightBorderColor() != rightStyle.getRightBorderColor())
        {
            return false;
        }
        if (leftStyle.getRotation() != rightStyle.getRotation())
        {
            return false;
        }
        if (leftStyle.getTopBorderColor() != rightStyle.getTopBorderColor())
        {
            return false;
        }
        if (leftStyle.getVerticalAlignment() != rightStyle.getVerticalAlignment())
        {
            return false;
        }

        Font leftFont = leftWorkbook.getFontAt(leftStyle.getFontIndexAsInt());
        Font rightFont = rightWorkbook.getFontAt(rightStyle.getFontIndexAsInt());

        if (leftFont.getBold() != rightFont.getBold())
        {
            return false;
        }
        if (leftFont.getColor() != rightFont.getColor())
        {
            return false;
        }
        if (leftFont.getFontHeight() != rightFont.getFontHeight())
        {
            return false;
        }
        if (!(leftFont.getFontName().equals(rightFont.getFontName())))
        {
            return false;
        }
        if (leftFont.getItalic() != rightFont.getItalic())
        {
            return false;
        }
        if (leftFont.getStrikeout() != rightFont.getStrikeout())
        {
            return false;
        }
        if (leftFont.getTypeOffset() != rightFont.getTypeOffset())
        {
            return false;
        }
        if (leftFont.getUnderline() != rightFont.getUnderline())
        {
            return false;
        }
        if (leftFont.getCharSet() != rightFont.getCharSet())
        {
            return false;
        }

        var leftDataFormatString = leftStyle.getDataFormatString();
        var rightDataFormatString = rightStyle.getDataFormatString();
        if (!leftDataFormatString.equals(rightDataFormatString))
        {
            if (rightDataFormat != leftStyle.getDataFormat())
            {
                return false;
            }
        }
        return true;
    }

    private CellStyle getCellStyle(CellStyle srcCellStyle)
    {
        CellStyle dstCellStyle = getSameCellStyle(srcCellStyle);
        if (dstCellStyle == null)
        {
            dstCellStyle = cloneCellStyle(srcCellStyle);
            // Using our custom cloneCellStyle as it will reuse existing font if it already exists
            // while cloneStyleFrom() will create a new font even if it already exists.
            //dstCellStyle = dstWorkbook_.createCellStyle();
            //dstCellStyle.cloneStyleFrom(srcCellStyle);
        }

        return dstCellStyle;
    }

    // This is preferred over cloneStyleFrom() because it will reuse an existing font
    // instead of always creating a new one.
    private CellStyle cloneCellStyle(CellStyle srcCellStyle)
    {
        // Create a new cell style
        Font srcFont = srcWorkbook_.getFontAt(srcCellStyle.getFontIndexAsInt());
        // Find a existing font corresponding to avoid to create a
        // new one
        Font dstFont = dstWorkbook_
                           .findFont(srcFont.getBold(), srcFont.getColor(), srcFont.getFontHeight(),
                                     srcFont.getFontName(), srcFont.getItalic(), srcFont.getStrikeout(),
                                     srcFont.getTypeOffset(), srcFont.getUnderline());
        if (dstFont == null)
        {
            dstFont = dstWorkbook_.createFont();
            dstFont.setBold(srcFont.getBold());
            dstFont.setColor(srcFont.getColor());
            dstFont.setFontHeight(srcFont.getFontHeight());
            dstFont.setFontName(srcFont.getFontName());
            dstFont.setItalic(srcFont.getItalic());
            dstFont.setStrikeout(srcFont.getStrikeout());
            dstFont.setTypeOffset(srcFont.getTypeOffset());
            dstFont.setUnderline(srcFont.getUnderline());
            dstFont.setCharSet(srcFont.getCharSet());
        }

        CellStyle dstCellStyle = dstWorkbook_.createCellStyle();
        dstCellStyle.setFont(dstFont);

        DataFormat dstDataFormat = dstWorkbook_.createDataFormat();
        String srcDataFormatString = srcCellStyle.getDataFormatString();
        short dstFormat = dstDataFormat.getFormat(srcDataFormatString);
        dstCellStyle.setDataFormat(dstFormat);

        dstCellStyle.setAlignment(srcCellStyle.getAlignment());
        dstCellStyle.setHidden(srcCellStyle.getHidden());
        dstCellStyle.setLocked(srcCellStyle.getLocked());
        dstCellStyle.setWrapText(srcCellStyle.getWrapText());
        dstCellStyle.setBorderBottom(srcCellStyle.getBorderBottom());
        dstCellStyle.setBorderLeft(srcCellStyle.getBorderLeft());
        dstCellStyle.setBorderRight(srcCellStyle.getBorderRight());
        dstCellStyle.setBorderTop(srcCellStyle.getBorderTop());
        dstCellStyle.setBottomBorderColor(srcCellStyle.getBottomBorderColor());
        dstCellStyle.setFillBackgroundColor(srcCellStyle.getFillBackgroundColor());
        dstCellStyle.setFillForegroundColor(srcCellStyle.getFillForegroundColor());
        dstCellStyle.setFillPattern(srcCellStyle.getFillPattern());
        dstCellStyle.setIndention(srcCellStyle.getIndention());
        dstCellStyle.setLeftBorderColor(srcCellStyle.getLeftBorderColor());
        dstCellStyle.setRightBorderColor(srcCellStyle.getRightBorderColor());
        dstCellStyle.setRotation(srcCellStyle.getRotation());
        dstCellStyle.setTopBorderColor(srcCellStyle.getTopBorderColor());
        dstCellStyle.setVerticalAlignment(srcCellStyle.getVerticalAlignment());
        return dstCellStyle;
    }

    private void copySheetSettings()
    {
        dstSheet_.setAutobreaks(srcSheet_.getAutobreaks());
        dstSheet_.setDefaultColumnWidth(srcSheet_.getDefaultColumnWidth());
        dstSheet_.setDefaultRowHeight(srcSheet_.getDefaultRowHeight());
        dstSheet_.setDefaultRowHeightInPoints(srcSheet_.getDefaultRowHeightInPoints());
        dstSheet_.setDisplayGuts(srcSheet_.getDisplayGuts());
        dstSheet_.setFitToPage(srcSheet_.getFitToPage());

        dstSheet_.setForceFormulaRecalculation(srcSheet_.getForceFormulaRecalculation());

        PrintSetup srcSheet_PrintSetup = srcSheet_.getPrintSetup();
        PrintSetup dstSheet_PrintSetup = dstSheet_.getPrintSetup();

        dstSheet_PrintSetup.setPaperSize(srcSheet_PrintSetup.getPaperSize());
        dstSheet_PrintSetup.setScale(srcSheet_PrintSetup.getScale());
        dstSheet_PrintSetup.setPageStart(srcSheet_PrintSetup.getPageStart());
        dstSheet_PrintSetup.setFitWidth(srcSheet_PrintSetup.getFitWidth());
        dstSheet_PrintSetup.setFitHeight(srcSheet_PrintSetup.getFitHeight());
        dstSheet_PrintSetup.setLeftToRight(srcSheet_PrintSetup.getLeftToRight());
        dstSheet_PrintSetup.setLandscape(srcSheet_PrintSetup.getLandscape());
        dstSheet_PrintSetup.setValidSettings(srcSheet_PrintSetup.getValidSettings());
        dstSheet_PrintSetup.setNoColor(srcSheet_PrintSetup.getNoColor());
        dstSheet_PrintSetup.setDraft(srcSheet_PrintSetup.getDraft());
        dstSheet_PrintSetup.setNotes(srcSheet_PrintSetup.getNotes());
        dstSheet_PrintSetup.setNoOrientation(srcSheet_PrintSetup.getNoOrientation());
        dstSheet_PrintSetup.setUsePage(srcSheet_PrintSetup.getUsePage());
        dstSheet_PrintSetup.setHResolution(srcSheet_PrintSetup.getHResolution());
        dstSheet_PrintSetup.setVResolution(srcSheet_PrintSetup.getVResolution());
        dstSheet_PrintSetup.setHeaderMargin(srcSheet_PrintSetup.getHeaderMargin());
        dstSheet_PrintSetup.setFooterMargin(srcSheet_PrintSetup.getFooterMargin());
        dstSheet_PrintSetup.setCopies(srcSheet_PrintSetup.getCopies());

        Header srcSheet_Header = srcSheet_.getHeader();
        Header dstSheet_Header = dstSheet_.getHeader();
        dstSheet_Header.setCenter(srcSheet_Header.getCenter());
        dstSheet_Header.setLeft(srcSheet_Header.getLeft());
        dstSheet_Header.setRight(srcSheet_Header.getRight());

        Footer srcSheet_Footer = srcSheet_.getFooter();
        Footer dstSheet_Footer = dstSheet_.getFooter();
        dstSheet_Footer.setCenter(srcSheet_Footer.getCenter());
        dstSheet_Footer.setLeft(srcSheet_Footer.getLeft());
        dstSheet_Footer.setRight(srcSheet_Footer.getRight());

        dstSheet_.setHorizontallyCenter(srcSheet_.getHorizontallyCenter());
        dstSheet_.setMargin(Sheet.LeftMargin, srcSheet_.getMargin(Sheet.LeftMargin));
        dstSheet_.setMargin(Sheet.RightMargin, srcSheet_.getMargin(Sheet.RightMargin));
        dstSheet_.setMargin(Sheet.TopMargin, srcSheet_.getMargin(Sheet.TopMargin));
        dstSheet_.setMargin(Sheet.BottomMargin, srcSheet_.getMargin(Sheet.BottomMargin));

        dstSheet_.setPrintGridlines(srcSheet_.isPrintGridlines());
        dstSheet_.setRowSumsBelow(srcSheet_.getRowSumsBelow());
        dstSheet_.setRowSumsRight(srcSheet_.getRowSumsRight());
        dstSheet_.setVerticallyCenter(srcSheet_.getVerticallyCenter());
        dstSheet_.setDisplayFormulas(srcSheet_.isDisplayFormulas());
        dstSheet_.setDisplayGridlines(srcSheet_.isDisplayGridlines());
        dstSheet_.setDisplayRowColHeadings(srcSheet_.isDisplayRowColHeadings());
        dstSheet_.setDisplayZeros(srcSheet_.isDisplayZeros());
        dstSheet_.setPrintGridlines(srcSheet_.isPrintGridlines());
        dstSheet_.setRightToLeft(srcSheet_.isRightToLeft());
        dstSheet_.setZoom(100);
        //copyPrintTitle(dstSheet_, srcSheet_);
    }
}
</pre>
</blockquote>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">73</post-id>	</item>
		<item>
		<title>Change Number of Monitors/Screen Resolution quickly with Shortcut or Batch file</title>
		<link>https://robsnotebook.com/restoremonitors7/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=restoremonitors7</link>
		
		<dc:creator><![CDATA[Rob]]></dc:creator>
		<pubDate>Tue, 10 Oct 2017 00:44:06 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://robsnotebook.com/?p=48</guid>

					<description><![CDATA[I recently fixed an issue in restoremonitors7 that makes it possible to create a shortcut on your desktop (or a batch file) to quickly change your screen resolution and/or number of active monitors to preset settings on Windows 7 and above. License terms are here. Basically it is free for personal and commercial uses. You [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I recently fixed an issue in <a href="https://github.com/rbresalier/monitortoggler">restoremonitors7</a> that makes it possible to create a shortcut on your desktop (or a batch file) to quickly change your screen resolution and/or number of active monitors to preset settings on Windows 7 and above.</p>
<p><a href="https://github.com/rbresalier/monitortoggler/blob/master/COPYING">License terms</a> are <a href="https://github.com/rbresalier/monitortoggler/blob/master/COPYING">here</a>. Basically it is free for personal and commercial uses.</p>
<p>You can download the restoremonitors7 executable from <a href="https://github.com/rbresalier/monitortoggler/raw/master/restoremonitors7.exe">here</a></p>
<p>This utility works on Windows 7 and newer windows versions.</p>
<p>Before using it, to setup the preset settings, you first use the Windows control panel to setup the desired monitors and screen resolution, and then save these settings at a command prompt by running:</p>
<p>restoremonitors7 -save &#8220;file_with_settings&#8221;</p>
<p>Later on when you want to restore this preset monitor/screen resolution configuration, do:</p>
<p>restoremonitors7 &#8220;file_with_settings&#8221;</p>
<p>You can create a shortcut on your desktop that calls &#8220;restoremonitors7 &#8220;file_with_settings&#8221;&#8221; so that you can quickly switch to your desired configuration.</p>
<p>I tried using other tools but each tool had some issues:</p>
<p><a href="http://www.nirsoft.net/utils/multi_monitor_tool.html">MultiMonitorTool</a>: After a reboot my MultiMonitorTool shortcut would not work properly anymore, restoremonitors7 works across reboots.</p>
<p><a href="https://12noon.com/?page_id=641">Display Changer II</a>: This tool from 12noon works, but it costs $499 for commercial use so the high cost was not an option. restoremonitors7 is currently free for commercial use.</p>
<p><a href="https://funk.eu/hrc/">Hotkey Resolution Changer</a> is not capable of having multiple monitors with different resolutions, restoremonitors7 is capable of multiple monitors with different resolutions.</p>
<p><a href="https://wizardsoft.nl/products/wsdisplaysettings">wsdisplaysettings</a> has the same working principles as restoremonitors7, but it has a nag screen and not free for commercial use. restoremonitors7 has no nag screen and is currently free for commercial use.</p>
]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">52</post-id>	</item>
		<item>
		<title>HDMI Audio popping noises on ATI Graphics Card &#8211; fixed!</title>
		<link>https://robsnotebook.com/hdmi-audio-causing-popping-noises-on-ati-graphics-card/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=hdmi-audio-causing-popping-noises-on-ati-graphics-card</link>
					<comments>https://robsnotebook.com/hdmi-audio-causing-popping-noises-on-ati-graphics-card/#comments</comments>
		
		<dc:creator><![CDATA[Rob]]></dc:creator>
		<pubDate>Thu, 17 Jun 2010 05:16:24 +0000</pubDate>
				<category><![CDATA[Troubleshooting]]></category>
		<guid isPermaLink="false">https://robsnotebook.com/hdmi-audio-causing-popping-noises-on-ati-graphics-card</guid>

					<description><![CDATA[When playing sound through my ATI HD4350 graphics card through the HDMI port, I was getting many popping sounds &#8211; and I found the fix. I am using Windows 7 Professional x64. The video was fine, but the audio had pops in it. I found that the cause of the problem was that my computer [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>When playing sound through my ATI HD4350 graphics card through the HDMI port, I was getting many popping sounds &#8211; and I found the fix.  I am using Windows 7 Professional x64.  The video was fine, but the audio had pops in it.</p>
<p>I found that the cause of the problem was that my computer was using the Microsoft HDMI audio driver instead of the ATI HDMI audio driver.</p>
<p>To fix this problem, I downloaded the latest Catalyst Control Center + drivers from the ATI website.  However, when I installed these drivers, it only installed the graphics driver, but did not override the Microsoft HDMI audio driver.</p>
<p>To install the HDMI audio driver on Windows 7, do the following:</p>
<ol>
<li>Go to Start->Control Panel->Sound, and select the &#8220;Playback&#8221; tab.</li>
<li>Right click on the &#8220;HDMI Output&#8221; playback device, and select &#8220;Properties&#8221;.</li>
<li>In the &#8220;general&#8221; tab, under &#8220;Controller Information&#8221;, if it says &#8220;Microsoft&#8221; anywhere, then it is using the Microsoft driver, and not the ATI driver.</li>
<li>Click on &#8220;Properties&#8221; in the &#8220;Controller Information&#8221; box</li>
<li>Go to the &#8220;Driver&#8221; tab, and click on &#8220;Update Driver&#8221;.</li>
<li>Click on &#8220;Browse my computer for driver software&#8221;, and choose the directory that the ATI driver install files were unzipped to.  In my case, this was the C:\ATI\Support\10-6_vista64_win7_64_dd_ccc_enu directory.  Make sure that &#8220;Include subfolders&#8221; is clicked.</li>
<li>Click on &#8220;Next&#8221;.  It will find the HDMI audio driver and will install it.</li>
<li>A reboot may or may not be necessary.  This got rid of the pops that I was hearing out of the HDMI output.</li>
</ol>
<p>This problem occurred on an ASUS EAH4350 desktop graphics card &#8211; but it could perhaps occur on other graphics cards as well.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robsnotebook.com/hdmi-audio-causing-popping-noises-on-ati-graphics-card/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">51</post-id>	</item>
		<item>
		<title>Print to PDF Without Getting Prompted for a Filename</title>
		<link>https://robsnotebook.com/print_to_pdf_no_filename_prompt/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=print_to_pdf_no_filename_prompt</link>
					<comments>https://robsnotebook.com/print_to_pdf_no_filename_prompt/#comments</comments>
		
		<dc:creator><![CDATA[Rob]]></dc:creator>
		<pubDate>Mon, 18 Aug 2008 03:37:59 +0000</pubDate>
				<category><![CDATA[Windows]]></category>
		<guid isPermaLink="false">https://robsnotebook.com/silently_print_pdf_to_file</guid>

					<description><![CDATA[Send print jobs to .pdf files silently so that your young kids don't waste your paper.]]></description>
										<content:encoded><![CDATA[<p><em>Since writing this article, I have found there is a much easier way to accomplish this &#8211; to use <a href="http://sourceforge.net/projects/pdfcreator/?abmode=1">PDFCreator</a>, which is free and has an autosave capability (which includes the date in the filename).  With PDFCreator, there is no need for cygwin, Perl and Redmon.  I am keeping this article posted however in case this other method is useful to anyone.</em></p>
<p>My 5 year old likes to hit the &#8220;print&#8221; button a little too much on her games, and 90% of the time she doesn&#8217;t go downstairs (network print) to the printer to see what she did.  I ended up wasting too much paper.</p>
<p>To solve this issue, I created a default printer that would silently print to a pdf file with a file name containing the date and time (YYMMDD_HHMMSS.pdf) to a directory of my choosing (instead of sending it to a physical printer).  This way anything that she prints will not waste paper, and if she really wants what she printed, we can print the pdf file.  It has the added benefit of saving anything she wanted to print in case she ever wants to print it again.</p>
<p>Using <a href="http://www.stat.tamu.edu/~henrik/GSPSprinter/GSPSprinter.html">this page</a> as a guide (but doing something different), I setup a postscript printer that prints to a redirected port.  Printing to a redirected port allows to send the postscript data to the STDIN of a program of my choosing.  The program that I chose was a perl script (created by me) that would create the desired filename (with the date and time) and then send the postscript to a pdf converter.</p>
<p>I had tried to accomplish this using the Acrobat Distiller (and telling it to not prompt for a filename), but I couldn&#8217;t get this to work to print out files with different names, so I settled on the solution documented here.</p>
<p>This guide copies some of its steps from <a href="http://www.stat.tamu.edu/~henrik/GSPSprinter/GSPSprinter.html">this page</a>.</p>
<p>Here is how I did this:</p>
<ol>
<li>If you don&#8217;t have it already, you need to have <a href="http://www.cygwin.com">cygwin</a> installed.  You will need the Perl and Ghostscript packages.</li>
<li>Download <a href="http://www.stat.tamu.edu/~henrik/GSPSprinter/redmon17.zip">redmon17.zip</a>, and install it.</li>
<li>Create the Virtual Postscript Printer and associate it to a newly created RPT1: port.
<ol>
<li>Using the <font color="#8b0000"><b>Add a printer</b></font> Wizard we add our virtual Postscript printer.
<div align="center">
		      <img decoding="async" alt="" src="/stepblog/downloads/printer/addprinter2.png" style="width: 503px; height: 392px;" />
		    </div>
<p>Select a <font color="#8b0000"><b>Local printer attached to this computer</b></font> option (the virtual printer will act like a local printer)</p>
<div align="center">
			  <img decoding="async" alt="" src="/stepblog/downloads/printer/addprinter3.png" style="width: 503px; height: 392px;" />
		    </div>
<p>Select <font color="#8b0000"><b>Create a new port</b></font> and choose <font color="#8b0000"><b>Redirected Port</b></font> as the <font color="#8b0000"><b>Type of Port</b></font>.</p>
<ul>
<li>Do not choose the <font color="#8b0000"><b>FILE:</b></font> or any other port here!</li>
<li>If you are using Windows XP/2000 and you do not have<font color="black"> a </font><font color="#8b0000"><b>Redirected Port</b></font> as an option then the installation of RedMon (above) failed. <i></i>You cannot continue until RedMon is properly installed. </li>
<li>Windows 98 will not list a redirected port here. For Windows 98 first select the printer (<font color="maroon"><b>HP&nbsp;Color LaserJet </b></font><b><font color="maroon">PS</font>) </b>and then select <font color="#8b0000"><b>FILE:</b></font> as the port. After creating the printer, add the <font color="#8b0000"><b>RPT1:</b></font> printer port under the <font color="#8b0000"><b>Details</b></font> tab of the printer properties. The process is <b><i>similar</i></b> to <a href="http://www.stat.tamu.edu/~henrik/GSWriter/GSWriter98.html">these steps</a>, but make sure to configure the printer and the port as described below.</li>
<li>The Windows 2000 screen looks <a href="/stepblog/downloads/printer/addprinter3-2k.png">significantly different</a> then the XP screen shown above. The functionality remains the same.</li>
</ul>
<p>Click on <font color="#8b0000"><b>Next</b></font> and</p>
<div align="center">
			    <img decoding="async" alt="" src="/stepblog/downloads/printer/addprinter4.png" style="width: 503px; height: 392px;" />
		    </div>
<p>accept the default Port Name of <font color="#8b0000"><b>RPT1:</b></font> (or <font color="#8b0000"><b>RPT2:</b></font>, etc.) by clicking <font color="#8b0000"><b>OK</b></font>. Now select the default printer to associate with this port.</p>
<div align="center">
			    <img decoding="async" alt="" src="/stepblog/downloads/printer/addprinter5.png" style="width: 503px; height: 392px;" />
		    </div>
<p>Select the HP printer <b><font color="#8b0000">HP Color Laserjet 4550 PS</font></b>. This is the virtual printer we are creating so even if you do not own this printer select this choice. Certain other (but not all) printer selection will work here. Important is that printer be a color Postscript printer. Some printers seem to give better font quality output then others. I have had good success with this one. <i>Under Windows 2000 select the <font color="#8b0000"><b>HP C LaserJet 4500-PS</b></font> printer.</i> Click on <font color="#8b0000"><b>Next</b></font> until you must name your printer:</p>
<div align="center">
			    <img decoding="async" alt="" src="/stepblog/downloads/printer/addprinter6.png" style="width: 503px; height: 392px;" />
		    </div>
<p>Name the printer <b><font color="#8b0000">GS PS Printer</font></b><font color="black"> (or anything else that suits your fancy) and yo</font>u probably may or may not want it to be your default printer. Click on <font color="#8b0000"><b>Next </b></font>and <font color="#8b0000"><b>Next</b></font> again on the Printer Sharing page until you reach the Print Test Page dialog box:</p>
<div align="center">
			    <img decoding="async" alt="" src="/stepblog/downloads/printer/addprinter7.png" style="width: 503px; height: 392px;" />
		    </div>
<p>Make sure you <span style="font-weight: bold;">do not</span> print a test page. Click on <font color="#8b0000"><b>Next</b></font> and then <font color="#8b0000"><b>Finish </b></font>to actually install the printer.</p>
<p>This printer will become our virtual Postscript printer. We can share it and print to it from other systems including a Windows 98 virtual machine (where most of my 5 year old&#8217;s games run) and Linux and Macintosh. The Windows 98 printer type should be set to &#8220;HP Color LaserJet PS&#8221; (as HP Color Laserjet 4550 PS is not available).  The Linux system can be configured to print to a <font color="#8b0000"><b>HP LaserJet 4050 Postscript</b></font> printer or simply a <font color="#8b0000"><b>Raw Print Queue</b></font>.</p>
<p>
			    </p>
</li>
</ol>
</li>
<li>Download the Perl Script, download <a href="/stepblog/downloads/printer/printpdf.pltxt">printpdf.pltxt</a> to c:\cygwin\bin (and rename it to printpdf.pl)</li>
<li>Modify the Perl script on line 6 ($outpath=&#8230;) in order to point to the directory where you would like to store the .pdf files.</li>
<li>Configure the RPT1: port:
<ul>
<li>Select <font color="#8b0000"><b>Properties</b></font><font color="black"> of the newly created</font><font color="#8b0000"><b> </b></font><b><font color="#8b0000">GS PS Printer</font></b>
<div align="center">
				  <img decoding="async" src="/stepblog/downloads/printer/configure.png" alt="" border="0" />
        </div>
<p>Under the <font color="#8b0000"><b>Ports</b></font> tab the correct port (created above) should already be selected (<b><font color="#8b0000">RPT1:</font></b> or higher). Click on <font color="#8b0000"><b>Configure Port&#8230;</b></font>:</p>
<div align="center">
				  <img decoding="async" alt="" src="/stepblog/downloads/printer/configure3.png" style="width: 586px; height: 441px;" />
			  </div>
<p>and fill out the dialog box as shown above.</p>
<p><b>Note:</b> The <font color="#8b0000"><b>Log File</b></font> button can be useful for tracking down problems should the printer fail to work properly.</p>
</li>
</ul>
</li>
<li>Now, if you send a job to this printer, a .pdf file with the name of YYMMDD_HHMMSS.pdf shall appear in the directory that you specified in the Perl script.  You can even share this printer over the network so that any virtual machines you have running old games for your child can print to this file also.</li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://robsnotebook.com/print_to_pdf_no_filename_prompt/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">50</post-id>	</item>
		<item>
		<title>Rob&#8217;s PERL Cookbook</title>
		<link>https://robsnotebook.com/perl_cookbook/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=perl_cookbook</link>
					<comments>https://robsnotebook.com/perl_cookbook/#comments</comments>
		
		<dc:creator><![CDATA[Rob]]></dc:creator>
		<pubDate>Wed, 18 Jun 2008 02:19:00 +0000</pubDate>
				<category><![CDATA[Perl]]></category>
		<guid isPermaLink="false">https://robsnotebook.com/perl_cookbook</guid>

					<description><![CDATA[My PERL cookbook, notes on how to do some common PERL stuff.]]></description>
										<content:encoded><![CDATA[<p>I occasionally write some PERL scripts.  Sometimes it can be many months between writing PERL scripts.  Whenever I start writing them again, I forget some basic things.  The last time I started writing some PERL again, I decided to write down the things that I was looking up.  Here is my PERL cookbook of common tasks.</p>
<h2>PERL Documentation</h2>
<p><a href="http://perldoc.perl.org/">http://perldoc.perl.org/</a></p>
<h2>Passing Parameters to Functions</h2>
<p>Parameters are passed to functions in the @_ list.</p>
<p>Typically, the following is done in a function:</p>
<blockquote>
<pre>sub function {
  my $parm1=shift @_;
  my $parm2=shift @_;

  ...function body...
}</pre>
</blockquote>
<p>Using &#8220;my&#8221; makes the scope of the variable only inside the function.  If there is no &#8220;my&#8221;, it is globally accessible.</p>
<h2>Constants/#defines</h2>
<p>See <a href="http://perldoc.perl.org/constant.html">&#8220;constant&#8221; on perldoc</a>.</p>
<blockquote>
<pre>use constant {
  CONST1 => 3,
  CONST2 => 4,
};</pre>
</blockquote>
<p>Use &#8220;CONST1&#8221; (without $ or @ preceeding it) in the code to refer to the constant &#8220;3&#8221;.</p>
<h2>Quotes</h2>
<p>To summarize the main difference between single and double quotation marks: <i>Single quotation marks do not interpret, and double quotation marks do. </i>That is, if you put something in single quotation marks, Perl assumes that you want the exact characters you place between the marks &#8212; except for the slash-single quote (\&#8217;) combination and double-slash (\\) combination. If you place text inside double quotation marks, however, Perl interprets variable names. Perl also interprets special characters inside double-quoted literal strings.</p>
<p><a href="http://www.dummies.com/WileyCDA/DummiesArticle/Contrasting-Single-and-Double-Quotes-in-Perl.id-254,subcat-PROGRAMMING.html">Quotes for dummies</a></p>
<p><a href="http://perldoc.perl.org/perlop.html#Quote-and-Quote-like-Operators">Perl documentation on quote operators</a>.</p>
<h2>File test operators</h2>
<p><a href="http://perldoc.perl.org/functions/-X.html">Reference</a></p>
<h3>To test if a file is a directory, do:</h3>
<blockquote>
<pre>if -d $file</pre>
</blockquote>
<h3>To test if a file exists</h3>
<blockquote>
<pre>if -e $file</pre>
</blockquote>
<h2>Chomping newlines</h2>
<p>The correct thing to do is:</p>
<blockquote>
<pre>chomp $var</pre>
</blockquote>
<p><a href="http://perldoc.perl.org/functions/chomp.html">Reference</a></p>
<p>This modifies the value of $var itself</p>
<p><b>DO NOT DO $var=chomp($var)</b>: that will put the return value of chomp() into $var, which is not the chomped $var, it is the number of characters </p>
<h2>Search/replace regular expression</h2>
<blockquote>
<pre>$var =~ s/(hi)there/$1/</pre>
</blockquote>
<p>The above example replaces &#8220;hithere&#8221; with just &#8220;hi&#8221;.</p>
<p>It takes $var as input, and also places the output into $var.</p>
<p>Notes:</p>
<ol>
<li><b>No quotes areound the regexp</b></li>
<li>$1, $2, etc can be used to substitute the grouped expressions</li>
</ol>
<h2>Initialize a list</h2>
<blockquote>
<pre>@list = ("item1","item2","item3");</pre>
</blockquote>
<h2>Get the size of a list</h2>
<blockquote>
<pre>$listsize = scalar(@list)</pre>
</blockquote>
<p>The scalar() function on a list returns the size of the list</p>
<h2>Find the length of a string in a variable</h2>
<blockquote>
<pre>$size=length($string)</pre>
</blockquote>
<h2>foreach loop</h2>
<p><a href="http://perldoc.perl.org/perlsyn.html#Foreach-Loops">perldoc for foreach</a></p>
<h2>Break out of a loop</h2>
<p>The &#8220;last&#8221; keyword is the equivalent of &#8220;break&#8221; in C.  It will exit out of a loop.</p>
<p>It is also more powerful than &#8220;break&#8221;, as it can exit out of an outermost loop.  For example:</p>
<blockquote>
<pre>LOOP_OUTER: for ($i=0;$i&lt;10;++i)
{
  for ($j=0;$j&lt;10;++i)
  {
    if (some condition)
      last LOOP_OUTER;
  }
}
</pre>
</blockquote>
<p>Use last without a label and it breaks out of the innermost loop.</p>
<p>Here is the <a href="http://perldoc.perl.org/functions/last.html">documentation for last</a>.</p>
<p>last doesn&#8217;t work with do/while.  You need to use a label for it.  See the end of the <a href="http://perldoc.perl.org/perlsyn.html#Statement-Modifiers">statement modifiers</a> section of perldoc.  Here is the example they give:</p>
<blockquote>
<pre> LOOP: { 
  do {
    last if $x = $y**2;
    # do something here
	 } while $x++ &lt;= $z;
  }
</pre>
</blockquote>
<h2>Skip to the next loop iteration</h2>
<p>The &#8220;next&#8221; keyword is the equivalent of &#8220;continue&#8221; in C.</p>
<p><a href="http://perldoc.perl.org/functions/next.html">documentation for next</a></p>
<h2>Forking and waiting on multiple processes, and the INT signal</h2>
<p><a href="http://perldoc.perl.org/functions/fork.html">fork()</a> will split the execution into child and parent.</p>
<p>It returns the child PID to the parent, and returns 0 to the child.</p>
<p>Use <a href="http://perldoc.perl.org/functions/waitpid.html">waitpid</a> to wait for the child to finish.  It can be non-blocking by using &#8220;WNOHANG&#8221; as the 2nd argument, or it can be blocking by using &#8220;0&#8221; as the 2nd argument.</p>
<p>The following example will wait for each child to finish in a blocking way (waitpid will block until at least one child is finished):</p>
<blockquote>
<pre>do {
  $kid = waitpid(-1, 0);
} while($kid>0);
</pre>
</blockquote>
<p>And with nonblocking:</p>
<blockquote>
<pre>do {
  $kid = waitpid(-1, WNOHANG);
} while($kid>0);
</pre>
</blockquote>
<p>It seems that when Ctrl-C is pressed on the parent it is passed to the children.  This is good.</p>
<p>Look at this example code: parent <a href="/stepblog/downloads/fork_test_parent.pl.txt">fork_test_parent.pl</a> invoking <a href="/stepblog/downloads/fork_test_child.pl.txt">fork_test_child.pl</a>.</p>
<h2>Handling Control-C</h2>
<p>See <a href="http://perldoc.perl.org/perlipc.html#Signals">here</a>.</p>
<p>&#8220;INT&#8221; is like a #define that can be used for the signal number for Ctrl-C.</p>
<p>These examples have a use of it: <a href="/stepblog/downloads/fork_test_parent.pl.txt">fork_test_parent.pl</a> invoking <a href="/stepblog/downloads/fork_test_child.pl.txt">fork_test_child.pl</a></p>
<h2>Signalling Ctrl-C to a process</h2>
<p>kill @pids</p>
<p>Index 0 of @pids must be the signal number.  &#8220;INT&#8221; can be used for Ctrl-C.</p>
<p>&#8220;kill&#8221; is used in the &#8220;cleanup&#8221; function of <a href="/stepblog/downloads/fork_test_parent.pl.txt">fork_test_parent.pl</a>.</p>
<h2>Expect.pm</h2>
<p><a href="http://search.cpan.org/~rgiersig/Expect-1.21/Expect.pod">Expect.pm documentation</a>.</p>
<h2>Command line parameters</h2>
<p>The @ARGV list has the command line parameters.  $ARGV[0] has the first parameter, it does not contain the executable name (unlike C).  Using &#8220;shift @ARGV&#8221; will move $ARGV[1] into $ARGV[0].</p>
<h2>Reading an input file</h2>
<blockquote>
<pre>$ret=open(FH,"$fname");
if (!$ret)
{ # File open failure.
 print STDERR "$fname was not opened successfully!!!\n";
 exit(1);
}

# File opened successfully
while ($inputline=&lt;FH&gt;)
{
 chomp($inputline);   # Remove trailing newline

 # Process $inputline

} # while ($inputline=&lt;FH&gt;)
close (FH);</pre>
</blockquote>
<h2>Writing to an output file</h2>
<blockquote>
<pre>$ret=open(FH,"&gt;$fname");
if(!$ret)
{ # File open is unsuccessful
  print STDERR "Can't open $fname for output!!!\\n";
  exit(1);
}
print FH "output line #1\\n";
print FH "output line #2\\n";
close (FH);</pre>
</blockquote>
<h2>Using split with whitespace between values</h2>
<blockquote>
<pre>($first_token,$second_token)=split(/\\s+/,$linein);</pre>
</blockquote>
<h2>Installing a module from CPAN</h2>
<p>May need admin privileges to do this.  If using cygwin, open a cygwin prompt as Administrator.  Below is an example of how I installed ExifTool</p>
<blockquote>
<pre>perl -MCPAN -e 'install Image::ExifTool'</pre>
</blockquote>
]]></content:encoded>
					
					<wfw:commentRss>https://robsnotebook.com/perl_cookbook/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">49</post-id>	</item>
		<item>
		<title>Windows Software that I Usually Install</title>
		<link>https://robsnotebook.com/windows-software-that-i-usually-install/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=windows-software-that-i-usually-install</link>
					<comments>https://robsnotebook.com/windows-software-that-i-usually-install/#comments</comments>
		
		<dc:creator><![CDATA[Rob]]></dc:creator>
		<pubDate>Wed, 18 Jun 2008 01:43:27 +0000</pubDate>
				<category><![CDATA[Tools]]></category>
		<guid isPermaLink="false">https://robsnotebook.com/windows-software-that-i-usually-install</guid>

					<description><![CDATA[A list of the software that I like to have installed on my Windows machines.]]></description>
										<content:encoded><![CDATA[<p>Here is a list of the software that I like to have installed on my Windows machines.</p>
<h2>Basic Tools</h2>
<p><a href="http://www.avast.com/">Avast Antivirus</a> &#8211; Free anti-virus on-demand scanner that is MUCH faster than McAffee</p>
<p><a href="http://www.betaclock.com/">betaclock</a> &#8211; Detailed time in system tray.  I use the following for my format string in order to show the date, time, and battery power in a 2 row system tray: ~%ac %timebatt~|~ddd, ~MMM d~|~h:mm~tt</p>
<p><a href="http://www.digsby.com/">Digsby</a> &#8211; An Instant Messaging tool that allows you to sign into multiple services at the same time.</p>
<p><a href="http://www.portablefreeware.com/?id=775">FastStone Capture v5.3</a> &#8211; Screen Capture software, version 5.3 is Freeware, newer versions are shareware, but v5.3 has all the functionality I need.  This <a href="http://lifehacker.com/379117/take-and-edit-screenshots-with-faststone-capture">Lifehacker article</a> has some additional freeware screen capture programs in the comments.</p>
<p><a href="http://www.hyperionics.com/files/index.asp">FileBox eXtender</a> &#8211; Add favorite folders to Explorer Windows and any File->Open/Save dialog</p>
<p><a href="http://www.mozilla.com/en-US/firefox/">Firefox</a> &#8211; My favorite web browser.</p>
<p><a href="http://www.foxitsoftware.com/pdf/reader_2/down_reader.htm">Foxit Reader</a> &#8211; PDF reader that is much faster than Acrobat.</p>
<p><a href="http://supercopier.sfxteam.org/modules/mydownloads/">SuperCopier 2</a> &#8211; (search for &#8220;English&#8221; on the webpage and click it) &#8211; Modifies Windows Explorer copying to not stop if there is a problem.  Also gives much more status for copies.</p>
<p><a href="http://www.freewebs.com/nerdcave/taskbarshuffle.htm">Taskbar Shuffle</a> &#8211; simple, small, free utility that lets you drag and drop your Windows taskbar buttons to rearrange them</p>
<p><a href="http://www.mozilla.com/en-US/thunderbird/">Thunderbird</a> &#8211; An email client program</p>
<p><a href="http://ccollomb.free.fr/unlocker/">Unlocker</a> &#8211; If you try to delete/rename a file and it is being used by another program, it will tell you which program is using it and will allow it to be unlocked if you want.</p>
<p><a href="http://www.realvnc.com/products/free/4.1/download.html">VNC</a> &#8211; Remote control your PC.  Don&#8217;t need to fill out the form on the VNC webpage, just click on &#8220;Proceed to Download&#8221; at the bottom of the page.</p>
<p><a href="http://pagesperso-orange.fr/pierre.g/xnview/enhome.html">XnView</a> &#8211; JPG and movie viewer</p>
<h2>Advanced Tools (Freeware)</h2>
<p><a href="http://www.astra32.com/">Astra32</a> &#8211; This program performs computer configuration analysis and provides detailed information on your computer hardware and its working modes.</p>
<p><a href="http://www.cygwin.com/">cygwin</a> &#8211; Unix utilies for Windows</p>
<p><a href="http://www.daemon-tools.cc/dtcc/download.php">Daemon Tools</a> &#8211; Mount CD/DVD ISO images on hard drive as a drive letter</p>
<p><a href="http://www.imgburn.com/">Imgburn</a> &#8211; Utility for creating CD/DVD .iso images (also does burning of images)</p>
<p><a href="http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx">Process Explorer</a> &#8211; Equivalent to Windows Task Manager but much more powerful.  Gives the full path to the executable that started a process (along with command line parameters).  Allows you to discover which processes are locking a file.  Allows you to change the priority of a process.</p>
<p><a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/">PuTTY</a> &#8211; Free SSH client (I usually use openssh for client and server under cygwin, but there are some occasions where PuTTY comes in handy).</p>
<p><a href="http://www.vmware.com/products/server/">VMWare Server</a> &#8211; Free virtualization program.</p>
<p><a href="http://winscp.net">WinSCP</a> &#8211; Free SFTP/FTP client for Windows with Norton Commander like dual pane interface.</p>
<h2>Non-Freeware Tools</h2>
<p><a href="http://www.scootersoftware.com/">Beyond Compare</a> &#8211; A fantastic tool for comparing directories and files.</p>
<p><a href="http://www.slickedit.com">SlickEdit</a> &#8211; A very powerful programmers editor &#8211; highly recommended.</p>
<p><a href="http://www.softpointer.com/tr.htm">Tag &#038; Rename</a> &#8211; Great utility for mass editing of tags in MP3/WMA files.</p>
<h2>Firefox Addons</h2>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/636">PDF Download</a> &#8211; Allows you to choose how to deal with PDFs &#8211; display in browser or open in PDF reader</p>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/125">SwitchProxy</a> &#8211; SwitchProxy lets you manage and switch between multiple proxy configurations</p>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/59">User Agent Switcher</a> &#8211; Adds a menu and a toolbar button to switch the user agent of the browser.</p>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/1419">IE Tab</a> &#8211; an extension from Taiwan, features: Embedding Internet Explorer in tabs of Mozilla/Firefox.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://robsnotebook.com/windows-software-that-i-usually-install/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">48</post-id>	</item>
		<item>
		<title>How To Setup a Free PHP Debugger using Eclipse PDT + XDebug</title>
		<link>https://robsnotebook.com/php_debugger_pdt_xdebug/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=php_debugger_pdt_xdebug</link>
					<comments>https://robsnotebook.com/php_debugger_pdt_xdebug/#comments</comments>
		
		<dc:creator><![CDATA[Rob]]></dc:creator>
		<pubDate>Thu, 12 Jun 2008 04:01:22 +0000</pubDate>
				<category><![CDATA[Tools]]></category>
		<guid isPermaLink="false">https://robsnotebook.com/php_debugger_pdt_xdebug</guid>

					<description><![CDATA[Step by step guide for setting up a free PHP Debugger using Eclipse PDT + XDebug]]></description>
										<content:encoded><![CDATA[<p>When I debug code, I find that a debugger is a very powerful tool.  With a debugger you can set breakpoints, step through code, watch variables, do a stack trace, and much, much more.  The eclipse PDT + XDebug offers a PHP debugger that you can use for free.  It also offers a full PDT IDE (for editing, &#8220;building&#8221;, and debugging your PHP projects), but I use eclipse+PDT+XDebug only as a debugger since I like to use <a href="http://www.slickedit.com">my favorite editor</a> for editing.  This guide shows how to setup eclipse+PDT+XDebug as your PHP Debugger.</p>
<p>This guide was written and tested using the <a href="http://download.eclipse.org/tools/pdt/downloads/release.php?release=R20080603">R20080603 &#8211; 1.0.3</a> PDT all in one package.  I also used XDebug 2.0.3.  With versions other than PDT R20080603 and XDebug 2.0.3, there may be subtle differences from what I wrote here, or things may not work.</p>
<ol>
<li>Make sure you have the latest version of <a href="http://www.java.com" target="_blank" rel="noopener noreferrer">Java</a> installed.</li>
<li>Make sure you have Apache+PHP installed (such as using the <a href="http://www.apachefriends.org/en/xampp.html" target="_blank" rel="noopener noreferrer">XAMPP</a> package)</li>
<li>Download XDebug
<ol>
<li>Go to the <a href="http://www.xdebug.org/" target="_blank" rel="noopener noreferrer">XDebug page</a></li>
<li>On right side of page, click on one of the Windows modules that matches your PHP version</li>
<li>Download the .dll file and remember its file name the directory that you saved it in (I save it in &#8220;c:\xampp\php\ext&#8221;).</li>
</ol>
</li>
<li>Install XDebug
<ol>
<li>Open your php.ini file in a text editor
<ul>
<li>In XAMPP, the default location for the php.ini file is &#8220;c:\xampp\apache\bin\php.ini&#8221;</li>
<li>If not using XAMPP, you can find the location of php.ini by browsing to a .php file on your server that calls the phpinfo() function.</li>
</ul>
</li>
<li>Either uncomment (recent versions of XAMPP have this in php.ini, but commented) or add:
<ul>
<li>Note:  substitute the right path/filename for your xdebug dll file</li>
</ul>
<blockquote>
<pre>[XDebug]
;; Only Zend OR (!) XDebug
; zend_extension_ts="C:\xampp\php\ext\php_xdebug.dll"
; Modify the filename below to reflect the .dll version of your xdebug
zend_extension_ts="C:\xampp\php\ext\php_xdebug-2.0.3-5.2.5.dll"
xdebug.remote_enable=true
xdebug.remote_host=127.0.0.1  ; if debugging on remote server,
                              ; put client IP here
xdebug.remote_port=9000
xdebug.remote_handler=dbgp
xdebug.profiler_enable=0
xdebug.profiler_output_dir="C:\xampp\tmp"
</pre>
</blockquote>
<p>                Note that &#8220;<i>xdebug.profiler_enable</i>&#8221; is set to 0 above instead of 1.  This is not the default in the XAMPP php.ini, and I recommend changing it to 0.  It was <a href="http://www.eclipse.org/newsportal/article.php?id=2098&#038;group=eclipse.tools.pdt#2098">suggested to me</a> to set this to 0 in order to not generate very large files.</p>
</li>
<li>Comment out any Zend Optimizer in php.ini because it is not compatible with XDebug.  For example, all of this should be commented out (using &#8220;;&#8221;):<br />
<blockquote>
<pre>[Zend]
; zend_extension_ts = "C:\xampp\php\zendOptimizer\lib\ZendExtensionManager.dll"
; zend_extension_manager.optimizer_ts = "C:\xampp\php\zendOptimizer\lib\Optimizer"
; zend_optimizer.enable_loader = 0
; zend_optimizer.optimization_level=15
;zend_optimizer.license_path =
</pre>
</blockquote>
</li>
<li>Restart your webserver for the php.ini to take effect.</li>
<li>Test that the Xdebug install was successful
<ol>
<li>Create a .php file that calls &#8220;phpinfo()&#8221;</li>
<li>Open the .php file with &#8220;phpinfo()&#8221; in your browser</li>
<li><a href="/stepblog/downloads/phpdebug/php-xdebug.jpg">Check for XDebug</a> in the phpinfo page.</li>
</ol>
</li>
</ol>
</li>
<li>Download Eclipse PDT
<ol>
<li>Go to the <a href="http://download.eclipse.org/tools/pdt/downloads/" target="_blank" rel="noopener noreferrer">Eclipse PDT Download page</a></li>
<li>On the download page, click the link for the latest release build in the &#8220;Build Name&#8221; column.</li>
<li>On the release build page, select the windows ZIP file in the &#8220;PDT All in One Package&#8221; area</li>
<li>On the mirror selection page, choose a mirror to download from and download the .zip file.</li>
</ol>
</li>
<li>Install Eclipse PDT all-in-one
<ol>
<li>There is no install .exe file to run.</li>
<li>Unzip the all-in-one zip file to a temporary directory.</li>
<li>Move the &#8220;eclipse&#8221; directory (created during unzip) to c:\eclipse (I tried using &#8220;c:\Program Files\eclipse&#8221; instead of c:\eclipse, but it didn&#8217;t seem to work for me, so use c:\eclipse).</li>
</ol>
</li>
<li>Execute Eclipse for the first time + Setup XDebug
<ol>
<li>Execute the c:\eclipse\eclipse.exe file.</li>
<li><a href="/stepblog/downloads/phpdebug/p1.jpg">&#8220;Workspace Launcher&#8221; dialog box</a> will appear, I just keep the default and press &#8220;OK&#8221;</li>
<li><a href="/stepblog/downloads/phpdebug/p2.jpg">&#8220;Welcome&#8221; screen</a>, click on &#8220;Workbench&#8221; icon on right side towards the middle.</li>
<li>Eclipse Workbench, do: <a href="/stepblog/downloads/phpdebug/p3.jpg">&#8220;Window-&gt;Open Perspective-&gt;PHP&#8221;</a></li>
<li><a href="/stepblog/downloads/phpdebug/p6.jpg">File-&gt;New-&gt;PHP Project</a>
<ol>
<li><a href="/stepblog/downloads/phpdebug/p7l.jpg">Project Name</a>: assign a name such as &#8220;Server-docroot&#8221;</li>
<li><a href="/stepblog/downloads/phpdebug/p7l.jpg">Project Contents</a>: uncheck &#8220;Default&#8221;, and browse to the document root of your web server. (<a href="/stepblog/downloads/phpdebug/p7.jpg">remote server example</a>)</li>
<li><a href="/stepblog/downloads/phpdebug/p7l.jpg">Click &#8220;Finish&#8221;</a></li>
<li>You&#8217;ll now see a <a href="/stepblog/downloads/phpdebug/p7a.jpg">screen</a> that gives you 2 options, choose the 1st option &#8220;Create project in <i>directoryName</i> (Deleting the project will delete the entire <i>directoryName</i> folder)&#8221;, and click &#8220;OK&#8221;.
<ul>
<li>Don&#8217;t ever delete this project from eclipse or it will delete your entire docroot.</li>
</ul>
</li>
</ol>
</li>
<li>Change to PHP Debug Perspective: <a href="/stepblog/downloads/phpdebug/p23.jpg">Window-&gt;Open Perspective-&gt;PHP Debug</a></li>
<li><a href="/stepblog/downloads/phpdebug/p27.jpg">Window-&gt;Web Browser</a>
<ol>
<li>If &#8220;0 Internal Web Browser&#8221; is available, you can choose that to have the browser inside eclipse.  I have found that this option is only present if IE is running before eclipse is launched, otherwise this option is not available.</li>
<li>If &#8220;0 Internal Web Browser&#8221; is not available, I found that &#8220;0 Default system Web Browser&#8221; doesn&#8217;t seem to work for me and that I have to choose either Firefox or IE in order for debugging to work.  If you really want to use the internal web browser, then quit out of eclipse, launch IE, and then launch eclipse again.  The internal web browser option should be available now.</li>
</ol>
</li>
<li>If your webserver is on a remote machine, do the following now:
<ol>
<li>Do <a href="/stepblog/downloads/phpdebug/p4.jpg">Window-&gt;Preferences</a></li>
<li>PHP-&gt;PHP Servers Window: <a href="/stepblog/downloads/phpdebug/p8.jpg">Click &#8220;New&#8221;</a></li>
<li><a href="/stepblog/downloads/phpdebug/p10.jpg">Name</a>: Provide a name to refer to this server in eclipse</li>
<li><a href="/stepblog/downloads/phpdebug/p10.jpg">URL</a>: Enter the URL of the document root of the remote server</li>
<li><a href="/stepblog/downloads/phpdebug/p10.jpg">Click &#8220;Next&gt;&#8221;</a></li>
<li>Server Path Mapping Window: <a href="/stepblog/downloads/phpdebug/p11.jpg">Click &#8220;Add:&#8221;</a></li>
<li><a href="/stepblog/downloads/phpdebug/p12.jpg">Path on Server</a>: if the docroot on the server is at c:\xampp\htdocs <em>on the server machine</em>, then put that here, otherwise put the docroot path of the server (remember, c: is the <em>server&#8217;s</em> c: drive)</li>
<li>Click on the radio for &#8220;Path in Workspace&#8221; and press the &#8220;Browse&#8221; button.  <a href="/stepblog/downloads/phpdebug/p13.jpg">Select the workspace resource corresponding to the docroot</a> (should be the only thing listed &#8211; this should be the name of the PHP project that you provided earlier &#8211; this guide used the project name &#8220;Server-docroot&#8221; ), and click &#8220;OK&#8221;</li>
<li><a href="/stepblog/downloads/phpdebug/p14.jpg">Click &#8220;OK&#8221;</a> (in &#8220;Add New Path Mapping&#8221; window)</li>
<li><a href="/stepblog/downloads/phpdebug/p15.jpg">Click &#8220;Finish&#8221;</a> (in &#8220;PHP Server Creation&#8221; window)
<ol>
<li>At this point, you <i>might</i> see a window titled<a href="/stepblog/downloads/phpdebug/p15a.jpg">&#8220;User Operation is Waiting&#8221;</a>, just be patient until this window disappears on its own before going to the next step.</li>
</ol>
</li>
<li><a href="/stepblog/downloads/phpdebug/p16.jpg">Click &#8220;OK&#8221;</a> in the Preferences-PHP Servers window.</li>
</ol>
</li>
<li><a href="/stepblog/downloads/phpdebug/p17.jpg">Run-&gt;Open Debug Dialog</a>
<ol>
<li>Double-click <a href="/stepblog/downloads/phpdebug/p18.jpg">&#8220;PHP Web Page&#8221;</a></li>
<li>&#8220;New configuration&#8221; is created as a sub-item under &#8220;PHP Web Page&#8221;, <a href="/stepblog/downloads/phpdebug/p19.jpg">highlight it</a></li>
<li><a href="/stepblog/downloads/phpdebug/p19.jpg">&#8220;Server Debugger&#8221;</a>: should be &#8220;XDebug&#8221;</li>
<li>&#8220;PHP Server&#8221;: choose <a href="/stepblog/downloads/phpdebug/p20.jpg">&#8220;Default Web Server&#8221;</a> (if your web server is on the same machine) or the <a href="/stepblog/downloads/phpdebug/p21.jpg">remote server</a> that you created earlier.</li>
<li><a href="/stepblog/downloads/phpdebug/p20.jpg">&#8220;File&#8221;</a>: Browse to a file in the project that should be launched in the browser for the debug session.</li>
<li>If &#8220;Auto Generate&#8221; is checked (<a href="/stepblog/downloads/phpdebug/p20.jpg">localhost example</a>, <a href="/stepblog/downloads/phpdebug/p21.jpg">remote server example</a>, a URL to the chosen file on the server should be auto-generated and should look correct.  If not (or if you want to add GET parameters), then it needs to be manually edited (after de-selecting &#8220;auto-generate&#8221;) to match the correct URL.
<ul>
<li>With the R20080603 PDT all-in-one package, it seems to add the <a href="/stepblog/downloads/phpdebug/p22a.jpg">project name into the URL</a> when auto-generate is checked, which is not correct.  You&#8217;ll need to <a href="/stepblog/downloads/phpdebug/p22b.jpg">uncheck auto-generate and remove the project name</a> from the URL to make it work.  It is unfortunate that it does this, the R20080103 (v1.0.2) release did not do that.</li>
</ul>
</li>
<li>Click <a href="/stepblog/downloads/phpdebug/p21.jpg">&#8220;Apply&#8221;</a></li>
<li>Click <a href="/stepblog/downloads/phpdebug/p22.jpg">&#8220;Close&#8221;</a></li>
</ol>
</li>
</ol>
</li>
<li>Run debug session
<ol>
<li>Do either: <a href="/stepblog/downloads/phpdebug/p24.jpg">Run-&gt;Debug</a> or F11 or click the <a href="/stepblog/downloads/phpdebug/p25.jpg">bug icon in toolbar</a>
<ol>
<li>If a window pops up at this point which states <a href="/stepblog/downloads/phpdebug/p25a.jpg">&#8220;The selection cannot be launched, and there are no recent launches&#8221;</a>, then do the following
<ol>
<li><a href="/stepblog/downloads/phpdebug/p17.jpg">Run-&gt;Open Debug Dialog</a></li>
<li>Highlight <a href="/stepblog/downloads/phpdebug/p19a.jpg">&#8220;New configuration&#8221;</a> under &#8220;PHP Web Page&#8221;, </li>
<li>Click the <a href="/stepblog/downloads/phpdebug/p19a.jpg">&#8220;Debug&#8221;</a> button</li>
</ol>
</li>
<li>If the debug session isn&#8217;t starting, and you are seeing in the lower right corner <a href="/stepblog/downloads/phpdebug/p19b.jpg">&#8220;Launching New_Configuration&#8221; with a progress bar that keeps moving</a>, then, then do the following:
<ol>
<li><a href="/stepblog/downloads/phpdebug/p19b.jpg">Click the button to the right of the progress bar</a>.</li>
<li>Now in the right pane you&#8217;ll see <a href="/stepblog/downloads/phpdebug/p19c.jpg">a red square button</a>, click it to get out of this faulty debug session.</li>
<li>If the web browser came up with the page you are trying to debug, it means XDebug is not installed on the server properly.  Go back and get XDebug installed on the server and try again.  One common mistake that causes this to occur is that you may have modified the wrong php.ini file, make sure you modified the right php.ini file.  You can test if XDebug is installed properly by opening a .php file in your browser that calls phpinfo() and see if XDebug is in the resulting page &#8211; make sure this is the case.  Also, make sure that <b>xdebug.remote_host is pointing to the machine running your debugger</b> (if you use a different machine to debug sometimes, you need to change this).</li>
<li>If the web browser did not come up, then in the pull-down menus, do &#8220;Window-&gt;Web Browser&#8221;</li>
<li>If it is set to &#8220;Default system Web Browser&#8221;, then this is the problem and you must switch off of it.
<ol>
<li>If &#8220;0 Internal Web Browser&#8221; is available, choose it.</li>
<li>If &#8220;0 Internal Web Browser&#8221; is not available, and you want to use the internal browser in eclipse instead of IE or Firefox, then quit eclipse, launch IE (and don&#8217;t close it), and launch eclipse again.  Before running your debug session, do &#8220;Window-&gt;Web Browser&#8221; and check that &#8220;0 Internal Web Browser&#8221; is available.  I have noticed that for some strange reason, if you don&#8217;t do &#8220;Window-&gt;Web Browser&#8221; before your first debug session, the internal web browser doesn&#8217;t seem to be available.</li>
<li>If you want to use Firefox or IE, or if &#8220;0 Internal Web Browser&#8221; is available, then choose Firefox or IE</li>
</ol>
</li>
</ol>
</li>
<li>If the &#8220;Confirm Perspective Switch&#8221; window pops up, check <a href="/stepblog/downloads/phpdebug/p26.jpg">&#8220;Remember my decision&#8221; and click &#8220;Yes&#8221;</a></li>
</ol>
</li>
<li>You now have a debug session going, have fun setting breakpoints, stepping through code, and looking at variables!</li>
</ol>
</li>
<li>Ending the debug session
<ol>
<li>I have noticed that once the php script runs to completion, the debug session is still running.  This is because if you navigate to another page it will also go through the debugger (this assumes that you have &#8220;Debug all pages&#8221; checked in Run-&gt;Open Debug Dialog;PHP Web Page/New Configuration;Advanced Tab).</li>
<li>To end the debug session, allow the current PHP script to run to completion and then <a href="/stepblog/downloads/phpdebug/p28.jpg">highlight the &#8220;Remote Launch&#8221;</a> in the &#8220;Debug&#8221; window and <a href="/stepblog/downloads/phpdebug/p29.jpg">press the red square button</a> just above it to terminate the session.</li>
</ol>
</li>
<li>Changing which file you want to debug
<ol>
<li>If you want to debug a different PHP file, you will need to go back to the <a href="/stepblog/downloads/phpdebug/p17.jpg">Run-&gt;Open Debug Dialog</a> screen, and in <a href="/stepblog/downloads/phpdebug/p22b.jpg">PHP Web Page/New_Configuration</a>, you&#8217;ll need to change both the file and the URL to the new PHP file.</li>
</ol>
</li>
<li>Happy Debugging!</li>
</ol>
<p>I haven&#8217;t used this debugger much yet as I have only gotten to set it up.  I&#8217;ll be adding more notes when I learn more.</p>
<p>One of the limitations I&#8217;ve found is that for the first page you navigate to, it seems that you can&#8217;t specify what is to be given in the &#8220;POST&#8221; data of the webpage.  If you want to debug the &#8220;POST&#8221; method to a PHP page, then make sure you have &#8220;Debug all pages&#8221; checked in Run-&gt;Open Debug Dialog;PHP Web Page/New Configuration;Advanced Tab.  Then you should let the PHP script run to display a web page with a form.  When you put the data into the form and submit it, the debugger will now allow you to debug this page with the POST data.</p>
<p>Useful Links:</p>
<p>
<a href="http://www.eclipse.org/pdt/">Eclipse PDT Homepage</a><br />
<a href="http://www.eclipse.org/pdt/docs.php">PDT Documentation Page</a><br />
<a href="http://www.eclipse.org/pdt/documents/XDebugGuide.pdf">XDebug Guide</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://robsnotebook.com/php_debugger_pdt_xdebug/feed/</wfw:commentRss>
			<slash:comments>106</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">47</post-id>	</item>
	</channel>
</rss>
