<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0">
    <channel>
    <title>Shuler Enterprises</title>
    <link>http://www.shulerent.com</link>
    <description>Technology + life = awesome</description>
    <language>en-us</language>           
    <generator>Nucleus CMS v3.40</generator>
    <copyright>&#169;</copyright>             
    <category>Weblog</category>
    <docs>http://backend.userland.com/rss</docs>
    <image>
        <url>http://www.shulerent.com/nucleus/nucleus2.gif</url>
        <title>Shuler Enterprises</title>
        <link>http://www.shulerent.com</link>
    </image>
    <item>
    <title>Using Process related API calls in VB.NET</title>
    <link>xml-rss2.php?itemid=478</link>
    <description><![CDATA[I'm working on an app that will monitor the number of GDI Objects of another process (in this case, the spooler)<br />
<br />
To do this in VB.NET requires an API call to GetGuiResources. While testing, I was using Process.GetProcesses to get a list of all the available processes, passed the handle of each process to the API function, and writing the result to a textbox.<br />
<br />
Problem was, all process that I did not own throw security errors, even when I set the app to run with elevated privs. The internet once again failed me, and I stumbled across the solution while browsing the system.diagnostics.process documentation on MSDN.<br />
<br />
The solution is to call Process.EnterDebugMode() before getting your process list and calling the API, then calling Process.LeaveDebugMode() when you are done.<br />
<br />
<a href="http://msdn.microsoft.com/en-us/library/system.diagnostics.process.enterdebugmode.aspx">MSDN EnterDebugMode Documentation</a><br />
<br />
<br />
Here is an example. remember to run with elevate privs, and create a multiline textbox called txtOut.<br />
<br />
<pre><br />
Public Class Form1<br />
  Declare Function GetGuiResources Lib "user32" (ByVal hProcess As Long, ByVal uiFlags As Long) As Long<br />
  ' uiFlags: 0 - Count of GDI objects<br />
  ' uiFlags: 1 - Count of USER objects<br />
<br />
  Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click<br />
    Dim procList As Process()<br />
<br />
    Dim TYPE_GDI As UInteger = 0<br />
<br />
    Process.EnterDebugMode()<br />
    procList = Process.GetProcesses<br />
<br />
    For Each proc As Process In procList<br />
      Dim objCnt As Long<br />
      Try<br />
        objCnt = GetGuiResources(proc.Handle, TYPE_GDI)<br />
      Catch ex As Exception<br />
        objCnt = -1<br />
      End Try<br />
<br />
      txOut.AppendText(proc.ProcessName & vbTab & "GDI: " & objCnt.ToString & vbNewLine)<br />
    Next proc<br />
<br />
    Process.LeaveDebugMode()<br />
<br />
<br />
  End Sub<br />
End Class<br />
<br />
</pre><br />
<br />
]]></description>
    <category>General</category>
    <comments>xml-rss2.php?itemid=478</comments>
    <pubDate>Mon, 22 Feb 2010 15:33:58 -0500</pubDate>
</item><item>
    <title>Getting Active Directory info for the current user in VB.net in 2 lines</title>
    <link>xml-rss2.php?itemid=474</link>
    <description><![CDATA[Don't listen to the internet - getting account information from active directory for the current user is simple and easy in Visual Basic .NET - particularly if you are using Framework 3.5.<br />
<br />
You don't need to do any stinking LDAP queries, or lookups, or credential passings - it's all made simple using System.DirectoryServices.AccountManagement. Observe.<br />
<br />
<br />
First, go to the references tab in project properties, click add reference, and find "System.DirectoryServices.AccountManagement" - no need to add "System.DirectoryServices".<br />
<br />
Now, in your application, add the following lines:<br />
<pre><br />
Dim currentADUser As System.DirectoryServices.AccountManagement.UserPrincipal<br />
currentADUser = System.DirectoryServices.AccountManagement.UserPrincipal.Current<br />
</pre><br />
(It's even simpler if you import the namespace)<br />
<br />
Poof. That's it! You are done.<br />
<br />
currentADUser is a strongly typed object containing attributes for most of the active directory properties you need = such as display name, email address, primary group membership, exchange mailbox info, etc, etc.<br />
<br />
<br />
Say you want to get the current user's email address. You could do it like so (after the previous code):<br />
<br />
<pre><br />
Dim userEmail as string = currentADUser.EmailAddress<br />
</pre><br />
<br />
That's it. 1 additional line.<br />
<br />
<br />
How about a concrete example - here is the problem I wanted to solve. Send an email message from the current user for error reporting - Make sure to change the To: email address, and the smtp server name, and this should be a drop-in solution:<br />
<pre><br />
  Private Sub report_error(ByVal errorMessage As String)<br />
    Dim currentADUser As System.DirectoryServices.AccountManagement.UserPrincipal<br />
    currentADUser = System.DirectoryServices.AccountManagement.UserPrincipal.Current<br />
    Dim mailClient As New System.Net.Mail.SmtpClient("smtpserver.company.local")<br />
    mailClient.Send(currentADUser.DisplayName & " <" & currentADUser.EmailAddress & ">", _<br />
                    "notifications@company.com", _<br />
                    "ERROR REPORT: Application error for " & currentADUser.DisplayName, _<br />
                    errorMessage)<br />
  End Sub<br />
</pre><br />
<br />
Hope this helps!]]></description>
    <category>General</category>
    <comments>xml-rss2.php?itemid=474</comments>
    <pubDate>Wed, 3 Feb 2010 12:28:40 -0500</pubDate>
</item><item>
    <title>Spam</title>
    <link>xml-rss2.php?itemid=472</link>
    <description><![CDATA[Sorry about the spam comments. Looks like I need to update nucleus. One of these days I will upgrade to wordpress...]]></description>
    <category>General</category>
    <comments>xml-rss2.php?itemid=472</comments>
    <pubDate>Sun, 31 Jan 2010 00:23:53 -0500</pubDate>
</item><item>
    <title>Virgin Mobile Broadband2go installer hangs</title>
    <link>xml-rss2.php?itemid=470</link>
    <description><![CDATA[If you have purchased a Virgin Mobile Broadband2Go pay as you go aircard (actually a novatell wireless ovation MC760), and find that the driver installation hangs on Windows 7, you will also find that the internet is little help.<br />
<br />
The solution is to disable USB Selective Suspending until Virgin Mobile releases a driver version later than 2.02.04.002<br />
<br />
<a href="http://shup.com/oqo/OQO%20Drivers/02+/2009.01.15/WWAN/Drivers/Novatel/Driver%20Installer%20Release%20Notes%20v2.02.04.002.pdf">http://shup.com/oqo/OQO%20Drivers/02+/2009.01.15/WWAN/Drivers/Novatel/Driver%20Installer%20Release%20Notes%20v2.02.04.002.pdf</a><br />
<br />
Here is the link to the release notes for the OQO drivers - which are newer that either the Virgin Mobile or Novatel generic drivers.<br />
<br />
You disable USB selective suspend from the advanced power settings screen.<br />
<br />
]]></description>
    <category>General</category>
    <comments>xml-rss2.php?itemid=470</comments>
    <pubDate>Sun, 6 Dec 2009 15:17:58 -0500</pubDate>
</item><item>
    <title>Installing VMware ESXi 4 vSphere from USB Drive</title>
    <link>xml-rss2.php?itemid=468</link>
    <description><![CDATA[If you need to install Vmware ESXi (or possibly ESX) 4 on a server without an optical drive - that is, install FROM a USB drive (not "to"), here is how to do in in Windows:<br />
<br />
1. Download and extract syslinux: <a href="http://syslinux.zytor.com/wiki/index.php/Download">http://syslinux.zytor.com/wiki/index.php/Download</a><br />
<br />
You will want syslinux-3.XX.zip - the latest at time of writing is syslinux-3.83.zip and it works fine.<br />
<br />
Extract it somewhere - lets say c:\syslinux<br />
<br />
2. Insert the USB drive if you have not already, make sure it is formatted fat32, and make note of the drive letter. For our example, we will use k:.<br />
<br />
<br />
3. Open a command prompt. (In windows Vista or 7, make sure to Run as Administrator)<br />
Change directory to the place you extracted syslinux \ win32.<br />
<br />
cd c:\syslinux\win32<br />
syslinux -m -f -a {drive}:<br />
where {drive} is the drive letter of the USB drive.<br />
<br />
4. Extract or copy the contents of the ESX iso image to the USB drive (you can use 7zip or winrar - no need to burn it)<br />
<br />
5. rename ISOLINUX.CFG to SYSLINUX.CFG<br />
<br />
<br />
That should do it.<br />
<br />
<br />
This is based on info from  the following sites - I didn't really change anything except the version, so if this doesn't work, they these:<br />
<a href="http://www.squishnet.com/?p=17">http://www.squishnet.com/?p=17</a><br />
<a href="http://www.vm-help.com/esx40i/ESXi_USB_install.php">http://www.vm-help.com/esx40i/ESXi_USB_install.php</a>]]></description>
    <category>General</category>
    <comments>xml-rss2.php?itemid=468</comments>
    <pubDate>Tue, 10 Nov 2009 15:51:49 -0500</pubDate>
</item><item>
    <title>Cracking the D-Link settings file</title>
    <link>xml-rss2.php?itemid=462</link>
    <description><![CDATA[The following is my description of how I figured out how to decode the D-Link settings file. If you don't care how I figured it out, skip to the end for VB.Net code samples and an executable.<br />
<br />
<br />
I have a DIR-628 wireless router that is having issues. There is a firmware update available, but my issue is not mentioned in the readme for the firmware.<br />
Normally when I upgrade the firmware, I will dump out a settings file, perform the upgrade, reload the settings file, and rejoice in the time saved not having to reconfigure. This time, though, I think I would like to have a clean slate - but there are some options that include passwords I don't recall offhand, so I figure I can just dump out the settings file, and take a look at it to get all that info...<br />
<br />
Wrong. The settings file is binary gobbledeygook.<br />
The default file name is gateway_settings.gws, and the file is about 175k.<br />
<br />
I gave Google a thorough searching, and had no luck - it looks like other people are searching for GWS format, or GWS file, but there were no meaningful pages that I could find.<br />
Next I downloaded trid_w32 - a neat little utility for identifying file types. I thought maybe it was compressed or something...<br />
No dice.<br />
<br />
<br />
So I decided to use the reverse engineering method - make some changes, and observe the result in the file.<br />
I created a firewall rule named "AAAAAAAAAAAA", and saved the settings; then renamed the rule to "BBBBBBBBBBBB", and use a nice binary comparison tool (HexCmp in this case) to see what my changes did.<br />
<br />
The A's within the file had become "78 79 7A 7B 7C 7D 7E..." - they were shifted, but that offset increased by 1 for each character. This I can fix!<br />
<br />
I then decoded the character before the first A - it was a ">". Could it be? Could this file really be XML??<br />
Worked backwards a couple more characters and had "name>AAAA..." - yes indeed! The decoded file will be XML!!<br />
<br />
The next question was where to begin - what will be the shift of the first character? If the file is xml, I can be pretty sure the first character is a "<" - and this is the first character of the .gws file.<br />
<br />
After much fooling around in VB.net, and battling with modulus math, I had the encoder formula:<br />
encodedByte = (positionNbr + CharacterCode) mod 256<br />
<br />
Decoding was a bit trickier, because as long as (position mod 256) + characterCode is less than 256, you can just subtract. If it is greater than 256, you have to work a bit harder. If I had more time, I bet there is a way to write a single formula to restore the character code, but I was able to do it with an IF statement.<br />
<br />
<br />
Here is the VB.net function for decoding a byte array containing the .gws file<br />
<pre><br />
  Function decodeGWS(ByRef encodedGWS As Byte()) As String<br />
    Dim chrMax As UInteger<br />
    Dim decodedGWS As Char()<br />
    chrMax = encodedGWS.GetUpperBound(0)<br />
    ReDim decodedGWS(chrMax)<br />
<br />
    For i As UInteger = 0 To chrMax<br />
      If encodedGWS(i) < (i Mod 256) Then<br />
        decodedGWS(i) = Chr((256 + encodedGWS(i)) - (i Mod 256))<br />
      Else<br />
        decodedGWS(i) = Chr(encodedGWS(i) - (i Mod 256))<br />
      End If<br />
    Next i<br />
<br />
    Return decodedGWS<br />
  End Function<br />
</pre><br />
<br />
And it works like a charm. The file is actually a great big XML containing all the available options.<br />
<br />
Here is the little utility I wrote to decode the file:<br />
<a href="http://www.shulerent.com/media/1/20090821-GWSCoder.zip">GWS Decoder Utility</a><br />
<br />
For completeness sake, I included encoder functionality, and I have verified that the output is identical to the original file when no changes are made to the xml file, but I really don't know what would happen if you tried to make changes to the XML and load it back onto your router. If you want to try it, don't come crying to me when your router gives up it's magic smoke, or your house burns down.<br />
<br />
Hopefully somebody finds this helpful!]]></description>
    <category>General</category>
    <comments>xml-rss2.php?itemid=462</comments>
    <pubDate>Fri, 21 Aug 2009 23:32:32 -0400</pubDate>
</item><item>
    <title>A better ALPS touchpad driver</title>
    <link>xml-rss2.php?itemid=460</link>
    <description><![CDATA[If you have a dell inspiron 1545 like I do, you might be happy with your laptop. Happy with everything except this godawful excuse for a touchpad! (and the missing bluetooth, and wireless-N - but these can be resolved)<br />
<br />
ALPS touchpads suck. They are jumpy, at the same time unresponsive and too responsive, the scroll feature never seems to work right the first time... so yeah. I don't like it.<br />
<br />
Turns out some of the issues can be mitigated by using Acer drivers. They are less customized, and include newer versions of various components. The scrolling is more reliable, and they don't freeze up under load like the Dell drivers.<br />
<br />
I used the drivers from here:<br />
<a href="http://drivers.softpedia.com/get/KEYBOARD-and-MOUSE/OTHERS/Acer-Aspire-3810TZ-Notebook-ALPS-Touchpad-Driver-752021101-for-Vista.shtml">http://drivers.softpedia.com/get/KEYBOARD-and-MOUSE/OTHERS/Acer-Aspire-3810TZ-Notebook-ALPS-Touchpad-Driver-752021101-for-Vista.shtml</a><br />
<br />
or search for Acer aspire ALPS drivers on google.<br />
<br />
Hope this helps!]]></description>
    <category>General</category>
    <comments>xml-rss2.php?itemid=460</comments>
    <pubDate>Wed, 19 Aug 2009 21:54:39 -0400</pubDate>
</item><item>
    <title>Essential Business Server 2008 .NET Framework 3.5 sp1 install fails</title>
    <link>xml-rss2.php?itemid=457</link>
    <description><![CDATA[After getting all three servers up to date when installing EBS 2008, you will likely find one update that refuses to install - .NET Framework 3.5 sp1.<br />
<br />
The EBS Team blog has a nice Powershell script that *should* fix it, but there's a bug in the script.<br />
<a href="http://blogs.technet.com/essentialbusinessserver/archive/2009/05/07/microsoft-net-framework-3-5-sp1-kb951847-fails-to-install-on-ebs-servers.aspx">Microsoft .NET Framework 3.5 SP1 (KB951847) Fails to install on EBS Servers</a><br />
<br />
At least, there is a bug when you try to run it after updating everything else (including the server to sp2).<br />
<br />
at the line that looks like :<br />
<pre><br />
$goodvalue = $badvalue.$frameworkguid -replace ("D\?\\", "C\?\\")<br />
</pre><br />
<br />
The replacement string should be "C?\". The search string requires the question mark and slash to be escaped, but the replacement string does not. It is supposed to replace "D?\" with "C?\", but instead it replaces it with "C\?\\" -- which exists even less than the original path!<br />
<br />
<br />
I have created two helpful scripts.<br />
<br />
First, if you have not already run the script from the EBS Blog, use this one instead:<br />
<a href="http://www.shulerent.com/media/1/20090815-dotnetfixup_fixed.ps1">dotnetfixup_fixed.ps1</a><br />
<br />
If you have used the bugged version of the script use this script to fix it. You will now be able to install the .NET updates.<br />
<a href="http://www.shulerent.com/media/1/20090815-repair_bugged_fixup.ps1">repair_bugged_fixup.ps1</a><br />
<br />
These are run from an elevated powershell prompt, not a command prompt.<br />
<br />
Good luck!]]></description>
    <category>General</category>
    <comments>xml-rss2.php?itemid=457</comments>
    <pubDate>Sat, 15 Aug 2009 18:53:50 -0400</pubDate>
</item><item>
    <title>Visual Studio 2008 ISO md5 checksum</title>
    <link>xml-rss2.php?itemid=455</link>
    <description><![CDATA[I had to recover some files from a messed up hard drive - one of those being my ISO for Visual Studio 2008 as downloaded from Microsoft Volume licensing / Software assurance.<br />
<br />
The file is nearly 4-gigs - I didn't want to re-download, but Microsoft neglected to share any sort of file hash (like they do on technet downloads)<br />
<br />
So I started the download using the Download Manager hoping a checksum would be available in the interface. No dice.<br />
<br />
After digging around my hard drive, I found the info file for the download manager at:<br />
<br />
C:\Users\<user>\AppData\Roaming\Download Manager\blahblah.dmc<br />
It's your standard microsoft style config with the heading "DLM Recovery Info" (I'd like to point out that this page will soon be the only instance of this phrase on the internets)<br />
<br />
And what do you know, it contains a line:<br />
md5=uhuhpt3QyTRBFTr56Tp7Ig==<br />
<br />
Now were I more encoding savvy I would have instantly recognized the double equals at the end as a base64 encoded string, but alas, I did not know about this. I converted from base64 -> ascii -> hex, and finally had the good old md5 hash we know and love :)<br />
<br />
So here it is:<br />
<br />
File name: SW_DVD9_Visual_Studio_Pro_2008_English_Core_MLF_X14-26326.ISO<br />
md5 hash: ba1ba1a6ddd0c93441153af9e93a7b22<br />
<br />
Maybe there is some other soul out there with a possible corrupt file who can benefit from this hash. Ok probably not, considering VS 2010 is around the corner, and nobody had posted it before.]]></description>
    <category>General</category>
    <comments>xml-rss2.php?itemid=455</comments>
    <pubDate>Sat, 27 Jun 2009 00:40:26 -0400</pubDate>
</item><item>
    <title>Fixing lost data in a data bound control that causes an exception</title>
    <link>xml-rss2.php?itemid=452</link>
    <description><![CDATA[Vusual Basic .NET 2008 is wonderful. It makes working with databases a breeze (sort of...) Using datasets and databindings, you can create a data driven application with very little hand-written code.<br />
<br />
Recently, a user of one of my apps encountered an unhandled error (yeah I know. Whoops.) "The value violates the MaxLength limit of this column" and was allowed to continue or quit. He chose continue, clicked save again, and even though it appeared to save, nothing actually saved.<br />
<br />
The exception happened when bindingsource.EndEdit() was called on the table containing the undersized field. Debugging showed that after the error occurs, the underlying datarow is reverted to the pre-modified state.<br />
<br />
It doesn't make sense - it might be simple to fix, it might be (probably is) my fault, but nonetheless the internet failed me in finding a solution, so I made one up.<br />
<br />
The values that the user had spent hours working on are still in the controls, but the underlying binding source has changed. If we push the changes from all the controls back out to the datarow, saving again will create the error again - as it should.<br />
<br />
You push the changes back by calling the WriteValue() function on the data binding for a data bound control ( dataTextBox.DataBindings(0).WriteValue() ). Because I didn't want to hard code anything, I looped through all the controls on the form.<br />
<br />
Here is the semi-pseudocode I cludged together to get the app working. Please let me know if there is a better way.<br />
<br />
<pre><br />
Sub commitChanges()<br />
  Try<br />
    myBindingSource.EndEdit<br />
<br />
  Catch ex as Exception<br />
    msgbox(ex.message)<br />
    updateAllBindings()<br />
  End try<br />
End Sub<br />
<br />
Sub updateAllBindings()<br />
  For Each contr As Control In Me.Controls<br />
    For Each cbind as Binding in contr.DataBindings<br />
      cbind.WriteValue()<br />
    Next cbind<br />
  Next contr<br />
End Sub<br />
</pre><br />
<br />
Note: if you use any containers (tabs, panels, flowlayout) you will probably have to create a separate loop for each subcontainer.<br />
<br />
<br />
<br />
Ideally, the app would warn the user when control is validated, but I guess dataset field restrictions are not pushed to the control (and I'm too lazy to hand update each and every one).<br />
<br />
Once again, I find it hard to believe I'm the first person to have this problem...]]></description>
    <category>General</category>
    <comments>xml-rss2.php?itemid=452</comments>
    <pubDate>Mon, 15 Jun 2009 17:02:27 -0400</pubDate>
</item>
  </channel>
</rss>