If you execute backup using SMO, after successful completion, I test the SqlError for null, considering that the backup completed without errors:
But, as you can see, it actually return an error of class 0 number 3014 meaning success.
So the question is:
Q: How can I find out if backup completed successfully or not, and how should I handle these messages and statuses cleanly?
I'm afraid that there are multiple of "gotchas" here that I don't want to bite me in the ass later when this code goes production :)
I agree there are multiple "gotchas" and I personally think Microsoft SMO events are poorly implemented as the ServerMessageEventArgs contains a Property Error which not always provides information about an error but messages about successful operations!!
As an example:
The "error" with code 4035 is an information message. Not an error.
The "error" with code 3014 is an information message that happens when completed successfully. Not an error
Also notice that the Information event does not always happen when an error has occurred. It actually happens whenever SQL Server sends a message that could be information about the operation that has finished successfully
I am also concerned about not handling the errors/success properly, but checking sqlError as Null is a bad idea since it will not be ever null and it will always contain some message about successful operation or an error. And assuming that Information event occurs when there is an error is also a bad idea.
I suggest to handle the errors through the SqlError.Number and depending on the SMO event it has been triggered.
I have made the following code to create a database backup. It is in VB.NET but in C# would be similar. It receives necessary parameters including a delegate where to invoke events (to be handled at GUI), a progress to report the percentage and error handling depending on event triggered and the SqlError.Number as mentioned
Public Sub BackupDatabase(databaseName As String, backupFileFullPath As String, optionsBackup As OptionsBackupDatabase, operationProgress As IProgress(Of Integer),
operationResult As Action(Of OperationResult)) Implements IDatabaseManager.BackupDatabase
Dim sqlBackup As New Smo.Backup()
sqlBackup.Action = Smo.BackupActionType.Database
sqlBackup.BackupSetName = databaseName & " Backup"
sqlBackup.BackupSetDescription = "Full Backup of " & databaseName
sqlBackup.Database = databaseName
Dim bkDevice As New Smo.BackupDeviceItem(backupFileFullPath, Smo.DeviceType.File)
sqlBackup.Devices.Add(bkDevice)
sqlBackup.Initialize = optionsBackup.Overwrite
sqlBackup.Initialize = True
sqlBackup.PercentCompleteNotification = 5
AddHandler sqlBackup.PercentComplete, Sub(sender As Object, e As PercentCompleteEventArgs)
operationProgress.Report(e.Percent)
End Sub
AddHandler sqlBackup.Complete, Sub(sender As Object, e As ServerMessageEventArgs)
Dim sqlMessage As SqlClient.SqlError = e.Error
Dim opResult As New OperationResult()
Select Case sqlMessage.Number
Case 3014
opResult.operationResultType = OperationResultType.SmoSuccess
opResult.message = "Backup successfully created at " & backupFileFullPath & ". " & sqlMessage.Number & ": " & sqlMessage.Message
Case Else
opResult.operationResultType = OperationResultType.SmoError
opResult.message = "ERROR CODE " & sqlMessage.Number & ": " & sqlMessage.Message
End Select
operationResult.Invoke(opResult)
End Sub
AddHandler sqlBackup.NextMedia, Sub(sender As Object, e As ServerMessageEventArgs)
Dim sqlMessage As SqlClient.SqlError = e.Error
Dim opResult As New OperationResult()
opResult.operationResultType = OperationResultType.SmoError
opResult.message = "ERROR CODE: " & sqlMessage.Number & ": " & sqlMessage.Message
operationResult.Invoke(opResult)
End Sub
AddHandler sqlBackup.Information, Sub(sender As Object, e As ServerMessageEventArgs)
Dim sqlMessage As SqlClient.SqlError = e.Error
Dim opResult As New OperationResult()
Select Case sqlMessage.Number
Case 4035
opResult.operationResultType = OperationResultType.SmoInformation
opResult.message = sqlMessage.Number & ": " & sqlMessage.Message
Case Else
opResult.operationResultType = OperationResultType.SmoError
opResult.message = "ERROR CODE " & sqlMessage.Number & ": " & sqlMessage.Message
End Select
operationResult.Invoke(opResult)
End Sub
Try
sqlBackup.SqlBackupAsync(smoServer)
Catch ex As Exception
Throw New BackupManagerException("Error backing up database " & databaseName, ex)
End Try
End Sub
I could be wrong, but I believe that the Complete event firing is the main indicator that the backup was successful - errors would be reported through the Information event.
Since the class of the error is 0 (or any value below 10), it indicates that it's an informational message, not an actual error (Error is somewhat misnamed). And 3014 is defined as the message that's sent when the backup is successful.
I'm not sure what other "gotchas" you're concerned with, since you haven't documented them.
Related
I have recently started experimenting with SQL Server Compact and EF6. I am currently using the model first approach and generating my classes and tables from it. I am curious though, about one thing. How can I get my program to dynamically create the database. It exists on my machine as I created it with the SQL Server Compact/SQLite toolkit, but when the program is deployed to client computers, the database will need to be created.
I would want to prompt them on first run for a good location, then create the entire DB schema and just use that in the future. I looked into this guide but vs started complaining about it not working because I didn't use a code-first approach.
If you need more info let me know! Thanks.
I have a little app I'm working on using SQL CE and EF and I deploy the template database when the app is installed (clickonce). Then I use a spash screen on application start to either load a previously created database or let the user create a new one.
When they create a new db I simply prompt them for a location and copy the template database out to their desired location with their desired name. I've also set it up to use the deployed database without giving them the opportunity have multiple database files.
We are dealing with a few pieces here as follows:
SQL CE database file
My stock/template .sdf file sits in my project folder and is included in the project within Visual Studio (I'm using 2015). Rightclick on the file in the Solution Explorer and select properties you want to set the following:
Build Action - Content
Copy to Output Directory - Copy always
Create global variable
Either use an existing module file or create a new one that looks like this:
Public Module Globals
Friend g_recipeData As RecipeEntities
End Module
Create setting for last file path
Rightclick on your project name in the solution explorer and pick Properties. Click the Settings tab and add a new setting as follows:
Name: lastpath
Type: String
Scope: User
Value:
Create splash screen form (frmSplash)
Mine looks like this:
Controls on the form are as follows:
txtFile
cmdSelectDatabase
cmdNew
cmdOpen
cmdExit
Splash Screen (frmSplash) Code
Region "Form Methods"
Private Sub OnFormLoad() Handles Me.Load
txtFile.Text = My.Settings.lastpath
If txtFile.Text <> "" Then
cmdOpen.Enabled = True
cmdOpen.Select()
Else
cmdNew.Select()
End If
End Sub
Private Sub FileSelect()
Try
Dim openFileDialog As New OpenFileDialog()
openFileDialog.Filter = "sdf files (*.sdf)|*.sdf|All files (*.*)|*.*"
openFileDialog.FilterIndex = 1
openFileDialog.RestoreDirectory = True
Dim result As DialogResult = openFileDialog.ShowDialog(Me)
If result = DialogResult.Cancel Then
cmdSelectDatabase.Select()
Exit Sub
End If
txtFile.Text = openFileDialog.FileName
If txtFile.Text <> "" Then
cmdOpen.Enabled = True
cmdOpen.Select()
My.Settings.lastpath = openFileDialog.FileName
My.Settings.Save()
Else
cmdOpen.Enabled = False
cmdSelectDatabase.Select()
End If
Catch ex As Exception
MessageBox.Show(ex.Message.ToString, "Application Error")
Application.Exit()
Finally
End Try
End Sub
Private Sub SetConnectionString()
Try
Dim providerName As String = "System.Data.SqlServerCe.4.0"
Dim datasource As String = txtFile.Text
Dim sqlCeBuilder As New SqlCeConnectionStringBuilder
sqlCeBuilder.DataSource = datasource
sqlCeBuilder.PersistSecurityInfo = True
g_SQLCeConnectionString = sqlCeBuilder.ConnectionString
Dim providerString As String = sqlCeBuilder.ToString()
Dim entityBuilder As New EntityConnectionStringBuilder()
entityBuilder.Provider = providerName
entityBuilder.ProviderConnectionString = providerString
entityBuilder.Metadata = "res://*/RecipeModel.csdl|res://*/RecipeModel.ssdl|res://*/RecipeModel.msl"
Dim c As System.Configuration.Configuration = ConfigurationManager.OpenExeConfiguration(System.Reflection.Assembly.GetExecutingAssembly().Location)
Dim section As ConnectionStringsSection = DirectCast(c.GetSection("connectionStrings"), ConnectionStringsSection)
g_EntityConnectionString = entityBuilder.ConnectionString
section.ConnectionStrings("RecipeEntities").ConnectionString = g_EntityConnectionString
c.Save(ConfigurationSaveMode.Modified)
ConfigurationManager.RefreshSection("connectionStrings")
Catch ex As Exception
MessageBox.Show(ex.Message.ToString, "Application Error")
Application.Exit()
End Try
End Sub
Private Sub CreateDatabase()
Try
Dim saveFileDialog As New SaveFileDialog()
saveFileDialog.Filter = "sdf files (*.sdf)|*.sdf"
saveFileDialog.Title = "Create Database"
saveFileDialog.FilterIndex = 1
If saveFileDialog.ShowDialog() = DialogResult.OK Then
File.Copy(Path.Combine(ApplicationDeployment.CurrentDeployment.DataDirectory, "rw.sdf"), saveFileDialog.FileName, True)
Dim strPathandFile As String = saveFileDialog.FileName
txtFile.Text = strPathandFile
My.Settings.lastpath = strPathandFile
My.Settings.Save()
cmdOpen.Enabled = True
End If
Catch ex As Exception
MessageBox.Show(ex.Message.ToString, "Application Error")
Application.Exit()
End Try
End Sub
Private Sub LoadMainApplication()
Try
Dim objNewForm As New FrmMain
objNewForm.Show()
Me.Close()
Catch ex As Exception
MessageBox.Show(ex.Message.ToString, "Application Error")
Application.Exit()
End Try
End Sub
End Region
Region "Event Handlers"
Private Sub cmdSelectDatabase_Click(sender As Object,
e As EventArgs) Handles cmdSelectDatabase.Click
FileSelect()
cmdOpen.Select()
End Sub
Private Sub cmdCancel_Click(sender As Object, e As EventArgs) Handles cmdExit.Click
Me.Close()
End Sub
Private Sub cmdOk_Click(sender As Object, e As EventArgs) Handles cmdOpen.Click
Me.Cursor = Cursors.WaitCursor
SetConnectionString()
LoadMainApplication()
Me.Cursor = Cursors.Default
End Sub
Private Sub txtFile_Validated(sender As Object, e As EventArgs) Handles txtFile.Validated
If txtFile.Text.Length = 0 Then
cmdOpen.Enabled = False
Else
cmdOpen.Enabled = True
End If
End Sub
Private Sub cmdNew_Click(sender As Object,
e As EventArgs) Handles cmdNew.Click
CreateDatabase()
SetConnectionString()
LoadMainApplication()
End Sub
Private Sub CatchEnterKey(ByVal sender As Object,
ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles txtFile.KeyPress, txtPassword.KeyPress
If e.KeyChar = ChrW(Keys.Enter) Then
cmdOk_Click(sender, e)
e.Handled = True
Exit Sub
End If
End Sub
Set global variable value
On the form of your main application (frmMain above) add the following to the constructor:
Public Sub New()
InitializeComponent()
g_recipeData = New RecipeEntities
End Sub
If you perform the above action when you create the variable in the module file then the connection string for the entity is set and you can't change it. You must set the connection string in app.config (using the above code) first and then the entity will use desired connection string when instantiated.
I think that's the basics for now. I highly recommend you reading through it again now that I'm done. I made some corrections and even added a step for the lastpath setting. Just hit me up if something isn't working or is confusing and I'll do my best to help. Good luck!
I'm attempting to use OOPFactory to parse 271 files. (source code here: https://x12parser.codeplex.com/SourceControl/latest) The part I'm struggling with at the moment is getting benefits information. (I can get subscriber and source information just fine).
I've followed the instructions in this post:
(Anyone translate a X12 271 Healthcare response) I can get an EligibilityBenefitDocument with the Subscriber and Source information, but the benefit information on the document winds up being either null, empty, or some other unhelpful value.
I've gone through the raw 271 data and verified that the information I'm looking for is indeed in there. (for reference, I've run multiple files from multiple payers)
I've traced through the both X12SteamReader and the X12Parser while they ran, and verified that the data made it all the way through the parser. It looks like things are working well with the parser. I'm not totally sure on how the EligiblityBenefitDocument is supposed to be generated. It looks like it uses some sort of xslt translation that doesn't seem to be working well for my 271 files. I've applied this tweak to my xslt file (https://x12parser.codeplex.com/workitem/2765) - it cleans up some null values, but still doesn't parse correctly.
What should I be looking at next?
It's possible that I'm using an unsupported EDI format. I'm not sure how to tell if that's the case
I've been programming for a long time, but I've never used the XSLT features of .NET Does anyone have any good links on where to get started there?
A quick solution would be AWESOME if anyone has one.
Thx!
=========
Edit 1:
Here is my code that kicks things off:
Dim ediFileString = path_to_my_file
Dim fstream = New FileStream(ediFileString, FileMode.Open, FileAccess.Read)
Dim service = New EligibilityTransformationService()
Dim benefitDoc = service.Transform271ToBenefitResponse(fstream)
Dim responses = benefitDoc.EligibilityBenefitResponses
I'm calling it from VB.NET instead of C#, but given that it all compiles down to MSIL, and that Source, Receiver, and Subscriber properties are all working, I don't think that's a reason why BenefitInfos would fail.
=========
Edit 2: including more code in response to a request for more detail of what I'm trying to do
Dim ediFileString = path_to_my_file
Dim fstream = New FileStream(ediFileString, FileMode.Open, FileAccess.Read)
Dim service = New EligibilityTransformationService()
Dim benefitDoc = service.Transform271ToBenefitResponse(fstream)
Dim responses = benefitDoc.EligibilityBenefitResponses
Dim strClient = ""
For Each client In benefitDoc.EligibilityBenefitResponses
Try
strClient = "MemberID: " + tidyNull(client.Subscriber.MemberId) + " Transaction Control Number: " + tidyNull(client.TransactionControlNumber) + Constants.vbCrLf
Catch ex As Exception
End Try
Try
strClient += "Member Name: " + tidyNull(client.Subscriber.Name.FirstName) + " " + tidyNull(client.Subscriber.Name.MiddleName) + " " + tidyNull(client.Subscriber.Name.LastName) + Constants.vbCrLf
Catch ex As Exception
End Try
Try
strClient += "Payer Name: " + tidyNull(client.Source.Name.LastName) + Constants.vbCrLf
Catch ex As Exception
End Try
Try
strClient += "Date of Birth: " + tidyNull(client.Subscriber.SerializableDateOfBirth) + Constants.vbCrLf
Catch ex As Exception
End Try
Try
strClient += "Address: " + tidyNull(client.Subscriber.Address.Line1)
strClient += " " + tidyNull(client.Subscriber.Address.Line2) + " " + Constants.vbCrLf
strClient += "Address: " + tidyNull(client.Subscriber.Address.City) + ", " + tidyNull(client.Subscriber.Address.StateCode) + ", " + tidyNull(client.Subscriber.Address.PostalCode) + Constants.vbCrLf
Catch ex As Exception
End Try
Dim results As List(Of EligibilityBenefitInformation)
Try
results = client.BenefitInfos.FindAll(AddressOf searchPlanActive)
If results.Count > 0 Then
strClient += "Active Coverage!" + Constants.vbCrLf
End If
Catch ex As Exception
strClient += "Coverage Type: Couldn't be found"
End Try
For Each benefit In client.BenefitInfos
If benefit.Amount IsNot Nothing Then
strClient &= " Code: " & benefit.Amount
End If
strClient &= " Percentage: " & benefit.Percentage
Try
strClient &= " CoverageLevel: " & benefit.CoverageLevel.Description
Catch ex As Exception
End Try
Try
strClient &= " InPlanNetwork: " & benefit.InPlanNetwork.Description
Catch
End Try
Try
strClient &= " PlanCoverageDescription: " & benefit.PlanCoverageDescription
Catch ex As Exception
End Try
'strClient &= " Messages: " & benefit.Messages.FindLast()
Try
strClient &= " Amount: " & benefit.Amount.Value
Catch ex As Exception
End Try
'strClient &= " Amount: " & benefit.AdditionalInfos
strClient &= Constants.vbCrLf
Next
MsgBox(strClient)
Next
=======
EDIT 3:
I'm attempting to process a 5010 file; OOPFactory says "The built-in specs contain all 4010 standards and some 5010 specifications" https:// x12parser.codeplex.com/ (can't post another working link yet due to lack of reputation points)
=======
Edit 4:
The failure seems to be happening in EligibilityTransformationService.cs on line 35. The correct information is making it into the XML, but is not deserializing properly.
var response = EligibilityBenefitDocument.Deserialize(responseXml);
I'm investigating why that might be.
=====
Edit 5:
In EligiblityTransformationService.cs, starting on line 32, the XML is transformed and then deserialized. The data in question is last seen on line 35 in the responseXml variable, but it never makes it into the response object.
It looks like an issue with the XSLT file.
transform.Transform(XmlReader.Create(new StringReader(xml)), new XsltArgumentList(), outputStream);
outputStream.Position = 0;
string responseXml = new StreamReader(outputStream).ReadToEnd();
var response = EligibilityBenefitDocument.Deserialize(responseXml);
I actually use this same method for my own work at the office. The issues we always run into is the response we receive is either null or random values. What we had to do was continue searching patient information until we found as many possible results that would come back to us. So for example, if we wanted to look up policy date information, we use:
var service = new EligibilityTransformationService();
EligibilityBenefitDocument eligibilityBenefitDocument = service.Transform271ToBenefitResponse(response271Stream);
eligibilityBenefitDocument.EligibilityBenefitResponses = eligibilityBenefitDocument.EligibilityBenefitResponses;
foreach (EligibilityBenefitInformation benefitInfo in eligibilityBenefitDocument.EligibilityBenefitResponses[0].BenefitInfos)
{
if (benefitInfo.InfoType.Code == "V")
return Tuple.Create(false, "Medicare cannot process");
if (benefitInfo.InfoType.Code == "6")
return Tuple.Create(false, "Inactive Policy");
if (benefitInfo.InsuranceType.Code == "HN" || benefitInfo.InsuranceType.Code == "12")
{
try
{
return Tuple.Create(false, "MADV " + benefitInfo.Identifications[0].Id + " " + benefitInfo.RelatedEntities[0].Name.LastName);
}
catch
{
return Tuple.Create(false, "MADV");
}
}
}
We still work off and on with these responses to try and get them as accurate as possible, but unfortunately, it seems like the codes can change for different payers, and its a bit time consuming figuring out how each one works until you get their possible response variations.
EDIT:
If there are no benefitInfos in the response, it means that you are submitting the incorrect patient Information. I have the following check in my program:
if(eligiblityBenefitDocument.EligiblityBenefitResponses[0].BenefitInfos.Count() < 1)
return "Subscriber Info Invalid"
I want to use built-in Open File dialog from my VSTO add-in. I have to set InitialFileName when showing the dialog. Unfortunately, this property does not exist in the Dialog class:
var Dlg = Word.Dialogs.Item(WdWordDialog.wdDialogFileOpen);
Dlg.InitialFileName = SomePath; //COMPILE ERROR: no such property
Try to cast it to FileDialog also doesn't work:
var Dlg = Word.Dialogs.Item(WdWordDialog.wdDialogFileOpen) as FileDialog;
Dlg.InitialFileName = SomePath; //RUNTIME EXCEPTION: null reference
What am I missing here?
Note: I'm using Add-in Express.
Got it. I had to cast my application object to Microsoft.Office.Interop.Word.Application to get access to the FileDialog member. The following code works:
var Dlg = ((Microsoft.Office.Interop.Word.Application)Word).get_FileDialog(MsoFileDialogType.msoFileDialogFilePicker);
Dlg.InitialFileName = STRfolderroot + STRfoldertemplatescommon + "\\" + TheModality + "\\" + TheModality + " " + TheStudyType + "\\";
Dlg.Show();
The Microsoft page in your post shows the property being used for the msoFileDialogFilePicker dialog but your code is using the wdDialogFileOpen. The example code on the MS page works fine but trying to use the property for wdDialogFileOpen also generates a run-time error.
So this works:
Sub ThisWorks()
Dim fd As FileDialog
Set fd = Application.FileDialog(msoFileDialogFilePicker)
Dim vrtSelectedItem As Variant
With fd
.InitialFileName = "C:\folder\printer_ink_test.docx"
'If the user presses the action button...
If .Show = -1 Then
For Each vrtSelectedItem In .SelectedItems
MsgBox "Selected item's path: " & vrtSelectedItem
Next vrtSelectedItem
'If the user presses Cancel...
Else
End If
End With
Set fd = Nothing
End Sub
But this fails:
Sub ThisFails()
Dim fd As Dialog
Set fd = Application.Dialogs(wdDialogFileOpen)
Dim vrtSelectedItem As Variant
With fd
' This line causes a run-time error
.InitialFileName = "C:\folder\printer_ink_test.docx"
'If the user presses the action button...
If .Show = -1 Then
For Each vrtSelectedItem In .SelectedItems
MsgBox "Selected item's path: " & vrtSelectedItem
Next vrtSelectedItem
'If the user presses Cancel...
Else
End If
End With
Set fd = Nothing
End Sub
Sorry for screenshot, I'm using my phone to answer.
This is how you do it for Excel according to the picture from google books: Globals.ThisWorkbook.ThisApplication.FileDialog
For MS Word according to this link, this is how its done:
Office.FileDialog dialog = app.get_FileDialog(
Office.MsoFileDialogType.msoFileDialogFilePicker);
//dialog.InitialFileName <-- set initial file name
dialog.Show();
I'm trying to redirect the stdout and stderr of a long process. It's an Exe that could take 40 minutes until it finished processing.
The issue is that if I run the EXE from command-line (cmd), stdout and stderr are displayed on console in a certain order,
and that's the order I'd like it to be redirected from my application, but it does not work. The order is changed when I use the following function, and can't find out what the reason is. I'd appreciate an advice.
This is the code I use:
Public numOutputLines As Integer = 0
Public sortOutput As StringBuilder = Nothing
Public Function ProcessTask3New(ByVal ExeName As String, ByVal arguments As String, ByRef stdout As String, ByRef stderr As String, ByRef ExitCode As Integer, _
Optional ByVal Filename As String = "", Optional ByVal IsDeleteTempLogFiles As Boolean = False) As Boolean
' This fucntion executes cmd commands and arguments,
' Function returns standard output and startdard error. stderr contains data if error was generated
Try
ProcessTask3New = True
Dim p As Process
Dim psi As ProcessStartInfo
Dim currentTime As System.DateTime
currentTime = System.DateTime.Now
If Filename <> "" Then Filename = Replace(Filename & ".", "\", "")
Dim tmpStdoutFilename As String = System.IO.Path.GetTempPath & "stdout." & Filename & currentTime.Ticks.ToString()
Dim tmpStderrFilename As String = System.IO.Path.GetTempPath & "stderr." & Filename & currentTime.Ticks.ToString()
netOutput = New StringBuilder
p = New Process
psi = p.StartInfo
psi.Arguments = psi.Arguments.Replace("/C " & Chr(34), "/C " & Chr(34) & Chr(34))
psi.FileName = ExeName
psi.UseShellExecute = False
psi.WindowStyle = ProcessWindowStyle.Minimized
' Redirect the standard output of the sort command.
' Read the stream asynchronously using an event handler.
psi.RedirectStandardOutput = True
psi.RedirectStandardError = True
psi.CreateNoWindow = True
sortOutput = New StringBuilder()
' Set our event handler to asynchronously read the sort output.
AddHandler p.OutputDataReceived, _
AddressOf SortOutputHandler
AddHandler p.ErrorDataReceived, AddressOf SortOutputHandler
If IsDebug Then Write2Log("ProcessTask3New: " + psi.FileName.ToString + " " + psi.Arguments.ToString)
Try
Write2Log(My.Computer.FileSystem.CurrentDirectory)
p.Start()
Catch w As System.ComponentModel.Win32Exception
Write2Log("ProcessTask3New: " & w.Message)
Write2Log("ProcessTask3New: " & w.ErrorCode.ToString())
Write2Log("ProcessTask3New: " & w.NativeErrorCode.ToString())
Write2Log("ProcessTask3New: " & w.StackTrace)
Write2Log("ProcessTask3New: " & w.Source)
Dim e As New Exception()
e = w.GetBaseException()
Write2Log("ProcessTask3New: " & e.Message)
End Try
' Start the asynchronous read of the sort output stream.
p.BeginOutputReadLine()
p.BeginErrorReadLine()
p.WaitForExit()
ExitCode = p.ExitCode
p.Close()
netOutput = Nothing
Catch ex As Exception
Write2Log("error at ProcessTask3New function: " & ex.ToString & " : " + ex.StackTrace)
End Try
End Function
Private Sub SortOutputHandler(ByVal sendingProcess As Object, _
ByVal outLine As DataReceivedEventArgs)
' Collect the sort command output.
If Not String.IsNullOrEmpty(outLine.Data) Then
numOutputLines += 1
Add the text to the collected output.
sortOutput.Append(Environment.NewLine + "[" _
+ numOutputLines.ToString() + "] - " _
+ outLine.Data)
End If
End Sub
Now the output.
This is how it looks when I run it from cmd window (this is GOOD):
Processing key file: vob_db.k01(1), total of 291 nodes
Processing delete chain: 1 node on delete chain. Processing nodes:
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%+++++++++70%+++++++++80%+++++++++90%+++++++++100 %
Processing key file: vob_db.k02(2), total of 1246 nodes
Processing delete chain: 2 nodes on delete chain. Processing nodes:
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%+++++++++70%+++++++++80%+++++++++90%+++++++++100 %
Processing key file: vob_db.k03(5), total of 1 node
Processing delete chain: 0 nodes on delete chain. Processing nodes:
100%
Processing key file: vob_db.k04(6), total of 277 nodes
Processing delete chain: 7 nodes on delete chain. Processing nodes:
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%+++++++++70%+++++++++80%+++++++++90%+++++++++100 %
(the lines like this one come from stderr.)
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%++
This is how it looks when I run it from my application (this is BAD):
ProcessTask3New: cmd.exe /C ""C:\Program Files
(x86).." -a -k -R -r1
-p29000 vob_db" E:\backup2\db db_VISTA Version 3.20 Database Consistency Check Utility Copyright (C) 1985-1990 Raima
Corporation, All Rights Reserved
------------------------------------------------------------------------ Processing key file: vob_db.k01(1), total of 291 nodes
------------------------------------------------------------------------ Processing key file: vob_db.k02(2), total of 1246 nodes
------------------------------------------------------------------------ Processing key file: vob_db.k03(5), total of 1 node
------------------------------------------------------------------------ Processing key file: vob_db.k04(6), total of 277 nodes
------------------------------------------------------------------------ Processing data file: vob_db.d01(0), total of 7107 records
------------------------------------------------------------------------ Processing data file: vob_db.d02(3), total of 20516 records
------------------------------------------------------------------------ Processing data file: vob_db.d03(4), total of 1 record
------------------------------------------------------------------------ Processing data file: vob_db.d04(7), total of 0 records
------------------------------------------------------------------------ Processing data file: vob_db.d05(8), total of 39938 records Processing
delete chain: 1 node on delete chain. 0 errors were encountered in 0
records/nodes
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%+++++++++70%+++++++++80%+++++++++90%+++++++++100% Processing delete chain: 2 nodes on delete chain. Processing nodes:
+++++++++10%+++++++++20%+++++++++30%+++++++++40%+++++++++50%+++++++++60%+++++++++70%+++++++++80%+++++++++90%+++++++++100% Processing delete chain: 0 nodes on delete chain. Processing nodes:
100%
Please advice. THANK YOU!
You have the option to "mix" the stdout and stderr, redirecting the stderr into stdout
cmd /c "commandToRun 2>&1"
Here we are asking cmd to execute some command and redirect the stream 2 (stderr) sending its output to stream 1 (stdout).
BUT, obviously you will not retrieve any data on stderr.
The reason behind different orders is that when in console, a single output stream is indeed assigned to both "standard output" and "error output", and when called by your application, there are two streams that are not synchronized, thus your SortOutputHandler events are called in any order (if there were extremely long pauses between writes to the outputs or flushes it could get ordered correctly by chance).
The only solution you have to get this well sorted is to ensure that there is a single stream. The problem is that I am not aware of a solution allowing this using the ProcessStartInfo class.
One possibility would be to start the process in "pause" mode, then redirect forcefully its standard error handle to the output handle, then let it run (as cmd.exe does)
I'm trying to find a way to get mail attachments (programaticaly) , and then open it... can someone tell me how to do this or point me to a right direction?
This is a VBA script (use in a Macro in Outlook) which will loop over all attachments in all selected items in the current folder and Save them to disk.
It should get you started and I don't think it would take much to add some kind of process launch rather than save logic to it.
Public Sub SaveAttachments()
'Note, this assumes you are in the a folder with e-mail messages when you run it.
'It does not have to be the inbox, simply any folder with e-mail messages
Dim Exp As Outlook.Explorer
Dim Sel As Outlook.Selection
Dim AttachmentCnt As Integer
Dim AttTotal As Integer
Dim MsgTotal As Integer
Dim outputDir As String
Dim outputFile As String
Dim fileExists As Boolean
Dim cnt As Integer
'Requires reference to Microsoft Scripting Runtime (SCRRUN.DLL)
Dim fso As FileSystemObject
Set Exp = Application.ActiveExplorer
Set Sel = Exp.Selection
Set fso = New FileSystemObject
outputDir = "C:\Path"
If outputDir = "" Then
MsgBox "You must pick an directory to save your files to. Exiting SaveAttachments.", vbCritical, "SaveAttachments"
Exit Sub
End If
Dim att As Attachment
'Loop thru each selected item in the inbox
For cnt = 1 To Sel.Count
'If the e-mail has attachments...
If Sel.Item(cnt).Attachments.Count > 0 Then
MsgTotal = MsgTotal + 1
'For each attachment on the message...
For AttachmentCnt = 1 To Sel.Item(cnt).Attachments.Count
'Get the attachment
Set att = Sel.Item(cnt).Attachments.Item(AttachmentCnt)
outputFile = att.FileName
outputFile = Format(Sel.Item(cnt).ReceivedTime, "yyyy-mm-dd_hhmmss - ") + outputFile
fileExists = fso.fileExists(outputDir + outputFile)
'Save it to disk if the file does not exist
If fileExists = False Then
att.SaveAsFile (outputDir + outputFile)
AttTotal = AttTotal + 1
End If
Set att = Nothing
Sel.Item(cnt).Close (Outlook.OlInspectorClose.olDiscard)
Next
End If
Next
'Clean up
Set Sel = Nothing
Set Exp = Nothing
Set fso = Nothing
'Let user know we are done
Dim doneMsg As String
doneMsg = "Completed saving " + Format$(AttTotal, "#,0") + " attachments in " + Format$(MsgTotal, "#,0") + " Messages."
MsgBox doneMsg, vbOKOnly, "Save Attachments"
Exit Sub
ErrorHandler:
Dim errMsg As String
errMsg = "An error has occurred. Error " + Err.Number + " " + Err.Description
Dim errResult As VbMsgBoxResult
errResult = MsgBox(errMsg, vbAbortRetryIgnore, "Error in Save Attachments")
Select Case errResult
Case vbAbort
Exit Sub
Case vbRetry
Resume
Case vbIgnore
Resume Next
End Select
End Sub
Look for the COM-reference of Outlook.
You can also use a macro written in vba to do this.