QSL Query, the Glassware I wrote for amateur radio operators using Google’s Go programming language, has been featured in the Eclectic Technology column of the December 2013 issue of QST! QST is the monthly journal of the Amateur Radio Relay League. It is free to all ARRL members and can also be found at most major bookstores and supermarkets.
I’ve been using Windows 8 Enterprise with Oracle VirtualBox on my MacBook Pro, which runs OS X Mavericks (10.9). Now that Windows 8.1 has been released, I decided to upgrade. I had read that the upgrade was fairly easy, and could be done through the Windows Store. This is not always the case – such as when you are running the Enterprise version.
If you are running the Enterprise version of Windows 8, you must install from DVD media, or a mounted .iso, or equivalent. I downloaded the iso file from MSDN and mounted it in OS X to install the upgrade. At this time, I came across an error I had never seen before:
“You can’t install Windows 8.1 because your processor doesn’t support CompareExchange128″.
Fortunately, this can be easily fixed. Open a Terminal Window and change directories to your VirtualBox.app directory. (This step may be unnecessary if your path is set up correctly.)
Next, at the command prompt, type:
vboxmanage setextradata [vmname] VBoxInternal/CPUM/CMPXCHG16B 1 <ENTER>
“[vmname]” should be the name of your VM, which in my case was “Windows 8 Enterprise”. Quotes are necessary if there are spaces in the name.
Restart your Windows 8 VM and try to install again!
Let’s say you have a whole lot of scheduled tasks you want moved into a subfolder in the Task Scheduler. Since you can’t just drag and drop the tasks, and must export the jobs into XML files to be imported, we will use similar commands as yesterday’s post.
For this, you will need an empty folder. I use C:\temp for this example. If your folder does not already exist, create one. Also, you will need a folder in the Task Scheduler GUI to exist. Create it using the Task Scheduler GUI.
Export all jobs you want to move into XML files:
1. Open the Command Prompt, and change to the C:\Windows\Tasks folder.
2. Type the following command and press Enter: FOR /R . %F in (*.job) do schtasks /Query /TN “%~nF” /XML > “C:\temp\%~nF.xml”
This will create all XML files in the C:\temp folder. You can then delete from that folder any XMLs for jobs that you don’t want moved.
Next, delete the jobs in the original folder either using the command line or through the GUI.
Lastly, enter the following command and press Enter:
FOR /R c:\temp %F in (*.xml) do schtasks /Create /S <<server name>> /RU <<username>> /RP <<password>> /XML “c:\temp\%~nF.xml” /TN “<<Task Scheduler folder name>>\%~nF”
This will recreate the job files and put the tasks into the folder (in the GUI) of your choosing.
On Windows XP and Windows Server 2003, Scheduled Tasks are stored as binary files with the “.job” extension. They are also stored in this manner on Windows Server 2008. Also, the jobs are stored in the same location in both operating systems, namely, “C:\Windows\Tasks”. So if you want to copy jobs from one to the other, you should just be able to copy the files, right? No, that would be too easy. For whatever reason, Microsoft chose to make it much more difficult to migrate jobs than this.
To successfully import jobs, several steps are required.
First of all, copy all “.job” files on the XP/2003 box into a folder of your choosing on the 2008 box. I’ll create “C:\temptasks” for this example.
Next, copy two files – schtasks.exe and schedsvc.dll – from C:\Windows\System32 on the source box into the C:\temptasks folder on the destination box.
Thirdly, copy (don’t move) the job files from the C:\temptasks folder into the C:\Windows\Tasks folder on the destination box.
Now for the fun part. To import a job, the following command must be issued from the Command Prompt:
schtasks /change /TN <<Scheduled Job Name>> /RU <<Username>> /RP <<Password>>
This command will only import one job – the one with whatever name you put in the command. If you have many jobs to import, this will not be practical. You’ll need a script to do this, but fortunately the script is simple.
By using a for loop and a basic regular expression, this can be done at the command line:
c:\temptasks>FOR /R . %F in (*.*) do schtasks /change /TN “%~nF” /RU <<Username>> /RP <<Password>>
This will import all of your job files into the Task Scheduler. The tasks may be in an enabled state, so be sure to check this if you don’t want them to run yet.
Note: This is an update to my last post.
I discovered that the version of the SAP CrystalReportViewer for VS2010 (13.0.2000.0) that I am using appears to have a bug that prevents the user from proceeding past page 2 when using the Next Page button. Pages can still be directly accessed by typing in the page number, but clicking the Next Page button keeps you on page 2.
I read quite a few possible solutions to this, such as moving the code that loads the Crystal Report from Page_Load to Page_Init, but this did not work for me. Also, there is an update to 13.0.2000.0 that might fix this issue, but I am not in a position to update the version of the SAP Crystal Reports software at present.
Fortunately, I was able to code around this bug. First, I disabled the navigation buttons on the viewer itself. Next, I put my own navigation buttons above the viewer component on the ASP.NET Web Form. Lastly, I wrote the code that handles the click events for these buttons.
Here is the code for the Reports.aspx page:
<%@ Page Language="VB" AutoEventWireup="true" CodeFile="Reports.aspx.vb" Inherits="Pages_Reports" %> <%@ Register Assembly="CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" Namespace="CrystalDecisions.Web" TagPrefix="CR" %> <!DOCTYPE html> <html> <head runat="server"> <title></title> <meta http-equiv="X-UA-Compatible" content="IE=9,chrome=1" /> </head> <body> <form id="form1" runat="server"> <div> <asp:ScriptManager ID="ScriptManager1" runat="server" AsyncPostBackTimeout="0" EnableHistory="True"> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional"> <ContentTemplate> <asp:Label ID="Label1" runat="server" Text="Page navigation: "></asp:Label> <asp:Button runat="server" ID="btnFirst" Text="|<--" ToolTip="Go to first page"/> <asp:Button runat="server" ID="btnPrev" Text="<<" ToolTip="Go to previous page"/> <asp:Button runat="server" ID="btnNext" Text=">>" ToolTip="Go to next page"/> <asp:Button runat="server" ID="btnLast" Text="-->|" ToolTip="Go to last page"/> <CR:CrystalReportViewer ID="CrystalReportViewer1" runat="server" AutoDataBind="true" HasCrystalLogo="False" GroupTreeStyle-ShowLines="True" Width="100%" Height="100%" EnableDatabaseLogonPrompt="False" ReuseParameterValuesOnRefresh="True" HasPageNavigationButtons="False" ShowAllPageIds="True" EnableParameterPrompt="False" /> </ContentTemplate> </asp:UpdatePanel> </div> </form> </body> </html>
…and the code file Reports.aspx.vb…
Imports CrystalDecisions.Shared Imports System.IO Imports CrystalDecisions.CrystalReports.Engine Imports CrystalDecisions.Web Partial Class Pages_Reports Inherits System.Web.UI.Page Protected strQueryString As String Protected intLastPage As Integer Protected intCurPage As Integer Protected Sub Page_Init(sender As Object, e As System.EventArgs) Handles Me.Init strQueryString = Request.QueryString.ToString() Page.Title = Replace(Request.QueryString("rpt").ToString(), ".rpt", "") If Not Page.IsPostBack Then 'Do nothing ElseIf Session(strQueryString) IsNot Nothing Then CrystalReportViewer1.ReportSource = Session(strQueryString) End If End Sub Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load If Not Page.IsPostBack Then Dim strReportName As String = Request.QueryString("rpt") Dim strSingleDate As String = Request.QueryString("single") Dim strBeginDate As String = Request.QueryString("begin") Dim strEndDate As String = Request.QueryString("end") Dim bSingleDate As Boolean = False Dim bMultiDate As Boolean = False Dim arrSingleDate() As String = _ Utilities.AppSettingsFunction.getValue("SingleDate").Split(",") Dim arrMultiDate() As String = _ Utilities.AppSettingsFunction.getValue("MultiDate").Split(",") If Array.IndexOf(arrSingleDate, strReportName) <> -1 Then bSingleDate = True bMultiDate = False ElseIf Array.IndexOf(arrMultiDate, strReportName) <> -1 Then bSingleDate = False bMultiDate = True End If Dim connInfo As New ConnectionInfo Dim rptDoc As New ReportDocument 'setup the connection connInfo = Functions.GetConnectionInfo() 'load the Crystal Report rptDoc.Load(Server.MapPath( _ Utilities.AppSettingsFunction.getValue("ReportFolder") _ & strReportName)) 'apply logon information For Each tbl As CrystalDecisions.CrystalReports.Engine.Table In rptDoc.Database.Tables Dim repTblLogonInfo As TableLogOnInfo = tbl.LogOnInfo repTblLogonInfo.ConnectionInfo = connInfo tbl.ApplyLogOnInfo(repTblLogonInfo) Next 'add required parameters If bSingleDate Then rptDoc.SetParameterValue("REPORT_DATE", strSingleDate & " 23:59:59") End If If bMultiDate Then rptDoc.SetParameterValue("BEGIN_DATE", strBeginDate & " 00:00:00") rptDoc.SetParameterValue("END_DATE", strEndDate & " 23:59:59") End If 'Set, bind, and display Crystal Reports Viewer data source Session(strQueryString) = rptDoc CrystalReportViewer1.ReportSource = Session(strQueryString) CrystalReportViewer1.ShowLastPage() CrystalReportViewer1.ShowFirstPage() Session(strQueryString + "_pagenum") = 1 Session(strQueryString + "_lastpagenum") = GetLastCRPageNumber() ElseIf Session(strQueryString) IsNot Nothing Then CrystalReportViewer1.ReportSource = Session(strQueryString) End If GetPageNums() End Sub Private Sub GetPageNums() intCurPage = Session(strQueryString + "_pagenum") intLastPage = Session(strQueryString + "_lastpagenum") ButtonsCheck() End Sub Private Sub SetCurPageNum(intPage As Integer) GetPageNums() Session(strQueryString + "_pagenum") = intPage ButtonsCheck() End Sub Protected Sub btnNext_Click(sender As Object, e As System.EventArgs) Handles btnNext.Click GetPageNums() If intCurPage < intLastPage Then SetCurPageNum(intCurPage + 1) CrystalReportViewer1.ShowNthPage(intCurPage + 1) Else CrystalReportViewer1.ShowNthPage(intCurPage) End If End Sub Protected Sub btnPrev_Click(sender As Object, e As System.EventArgs) Handles btnPrev.Click GetPageNums() If intCurPage > 1 Then SetCurPageNum(intCurPage - 1) CrystalReportViewer1.ShowNthPage(intCurPage - 1) Else CrystalReportViewer1.ShowNthPage(intCurPage) End If End Sub Private Function GetCRPageNumber() As Integer Dim vi As ViewInfo = CrystalReportViewer1.ViewInfo Return vi.PageNumber End Function Private Function GetLastCRPageNumber() As Integer Dim vi As ViewInfo = CrystalReportViewer1.ViewInfo Return vi.LastPageNumber End Function Protected Sub ButtonsCheck() If intCurPage = 1 Then btnFirst.Enabled = False btnPrev.Enabled = False Else btnFirst.Enabled = True btnPrev.Enabled = True End If If intCurPage = intLastPage Then btnLast.Enabled = False btnNext.Enabled = False Else btnLast.Enabled = True btnNext.Enabled = True End If End Sub Protected Sub CrystalReportViewer1_Navigate(source As Object, e As CrystalDecisions.Web.NavigateEventArgs) Handles CrystalReportViewer1.Navigate SetCurPageNum(e.NewPageNumber) End Sub Protected Sub btnFirst_Click(sender As Object, e As System.EventArgs) Handles btnFirst.Click CrystalReportViewer1.ShowFirstPage() GetPageNums() End Sub Protected Sub btnLast_Click(sender As Object, e As System.EventArgs) Handles btnLast.Click CrystalReportViewer1.ShowLastPage() GetPageNums() End Sub End Class