Mutex not locking and using not releasing file handle - vb.net

I am having problems getting a file handle to close properly. I have tried to use an additional Mutex to ensure only one thread has access to this file at a time.
As far as I understand it the Using construct should ensure that the file handle is released properly, and the Mutex should ensure that this code can only run in 1 thread at a time.
The error occurs when the logger is called multiple times in rapid succession.
The gethashcode was an attempt to verify that the mutex instance is the same.
Error Message:
An unhandled exception of type 'System.IO.IOException' occurred in mscorlib.dll
The process cannot access the file '****\LOG.log' because it is being used by another process.
Source:
Imports System.IO
Imports System.Net.Mail
Imports System.Threading
Public NotInheritable Class FileLogger
Private Shared ReadOnly _instance As New Lazy(Of FileLogger)(Function() New FileLogger(), System.Threading.LazyThreadSafetyMode.ExecutionAndPublication)
Public LOG_LEVEL As Integer = 4
Public LEVELS As New Dictionary(Of Double, String)
Private Shared strFile As String = "LOG.log"
Public Shared FileLoc As New Mutex()
Public Shared ReadOnly Property getLogger() As FileLogger
Get
Return _instance.Value
End Get
End Property
Private Sub New()
Dim strFile As String = "yourfile.log"
LEVELS.Add(0, "FATAL ")
LEVELS.Add(1, "CRITICAL")
LEVELS.Add(2, "ERROR ")
LEVELS.Add(3, "INFO ")
LEVELS.Add(4, "DEBUG ")
LEVELS.Add(2.5, "WARNING ")
End Sub
Public Sub writeEntry(ByVal message As String, ByVal level As Double)
If level <= LOG_LEVEL Then
Dim log_str As String = String.Format("{0} - in: {3} - {1}: {2}", DateTime.Now.ToString, LEVELS(level), message, Thread.CurrentThread.ManagedThreadId)
Console.WriteLine(log_str)
If level < 3 Then ' warning or greater write to file else just console
Console.WriteLine(FileLoc.GetHashCode())
FileLoc.WaitOne(Timeout.Infinite)
Using sw As StreamWriter = New StreamWriter(strFile, True) '<-- Debugger points to this line
sw.WriteLine(log_str)
End Using
FileLoc.ReleaseMutex()
End If
If level <= 2 Then 'if error or greater send email
FileLoc.WaitOne(Timeout.Infinite)
Dim mail As New MailMessage
mail.To.Add("email")
mail.From = New MailAddress("email")
mail.Subject = "Error on MC Server (SERVERNAME)"
mail.Body = log_str
mail.IsBodyHtml = True
mail.Attachments.Add(New Attachment(strFile))
Dim smtp As New SmtpClient
smtp.Host = "IPADDR"
smtp.Send(mail)
FileLoc.ReleaseMutex()
End If
End If
End Sub
End Class

The email section was not closing the file correctly. wrapping this in a using construct fixed the issue.
I also ended up implementing the SyncLock construct around the entire operation.
as some of the comments have pointed out the mutex may or may not have been doing what it was supposed to, but the file handle was still open from the attachment operation.
Public Sub writeEntry(ByVal message As String, ByVal level As Double)
SyncLock FileLoc
If level <= LOG_LEVEL Then
Dim log_str As String = String.Format("{0} - in: {3} - {1}: {2}", DateTime.Now.ToString, LEVELS(level), message, Thread.CurrentThread.ManagedThreadId)
Console.WriteLine(log_str)
If level < 3 Then ' warning or greater write to file else just console
Console.WriteLine(FileLoc.GetHashCode())
Using sw As StreamWriter = New StreamWriter(strFile, True)
sw.WriteLine(log_str)
End Using
End If
If level <= 2 Then 'if error or greater send email
Using at As Attachment = New Attachment(strFile)
Dim mail As New MailMessage
mail.To.Add("email")
mail.From = New MailAddress("email")
mail.Subject = "Error on MC Server (servername)"
mail.Body = log_str
mail.IsBodyHtml = True
mail.Attachments.Add(at)
Dim smtp As New SmtpClient
smtp.Host = "IPADDR"
smtp.Send(mail)
End Using
End If
End If
End SyncLock
End Sub

Related

Receive many file with server

I use a program to receive file that client send with specific port.
The problem is when a lot of client send file to this server, it wait to receive file in order, it receive files consecutive.
Now i need help to change this code that it received files Parallel.
For example 10 client, send file to this server.it receive all file in order, but i need it receive them Parallel.
I hope you understand what i want.
Imports System.Net
Imports System.Net.Sockets
Imports System.Threading
Imports System.IO
Module Module1
Public destinationfolder As String
Dim rcf As New RecievedFile
Public port As String
Sub Main()
Console.Title = "B64S Server"
Console.WindowHeight = 30
DrawGraphics(2)
Console.ForegroundColor = ConsoleColor.Gray
Console.WriteLine(" Created by: Turbocharged Chameleon")
DrawGraphics(2) ''draws some graphics from another sub
DrawGraphics(0)
DrawGraphics(2)
Console.ForegroundColor = ConsoleColor.White
Console.WriteLine("Destination Folder:")
destinationfolder = Console.ReadLine() ''reads line for destination folder
Console.WriteLine("Port:")
port = Console.ReadLine() ''reads line and sets the port
If Directory.Exists(destinationfolder) = False Then
MsgBox("destination folder doesn't exist!")
End ''ends program if folder doesn't exist
End If
Console.Clear()
''wait
DrawGraphics(1)
rcf.Threader = New Thread(New System.Threading.ThreadStart(AddressOf rcf.enter code hereRecieve))
rcf.Threader.Start() ''starts listening on port for incoming data
End Sub
Private Sub DrawGraphics(ByVal int As Integer)
If int = 0 Then
Console.ForegroundColor = ConsoleColor.Gray
Console.WriteLine("MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM")
Console.WriteLine("MMMMMMMMMMMMMM$,.........$MMMMOMMMMMMMMM")
Console.WriteLine("MMMMMMMMMMM8,,......... .. M....MMMMMMM")
ElseIf int = 1 Then
Console.ForegroundColor = ConsoleColor.Gray
Console.WriteLine("MMMMMMMMMMMMMMMII+++:::::==+++??$$$MMMMM")
Console.WriteLine("MMMMMMMMMMII???~~.............~~$$$MMMMM")
Console.WriteLine("MMMMMMMMMMII???~~.............~~$$$MMMMM")
ElseIf int = 2 Then
Console.ForegroundColor = ConsoleColor.Red
Console.WriteLine("----------------------------------------")
End If
End Sub
End Module
and Recieved File Class:
Public Class RecievedFile
Public Threader As Thread
Dim TCPListener As TcpListener
Dim Socket As Socket
Sub Recieve()
Try
TCPListener = New TcpListener(IPAddress.Any, port)
TCPListener.Start()
While True
Try
Socket = TCPListener.AcceptSocket
Dim MyNetworkStream As NetworkStream = New NetworkStream(Socket)
Dim mystreamreader As StreamReader = New StreamReader(MyNetworkStream)
Console.WriteLine("Recieving file...")
Dim str As String = mystreamreader.ReadToEnd
Console.WriteLine(str)
Dim fn As String = str.Remove(str.IndexOf("#"))
Dim filenamelength As Integer = fn.Length
Dim b64string As String = str.Substring(str.IndexOf("#") + 1)
Console.WriteLine("BS64")
Dim binaryData() As Byte = Convert.FromBase64String(b64string)
Console.WriteLine("done")
If My.Computer.FileSystem.FileExists(destinationfolder & "\" & fn) Then
System.IO.File.Delete(destinationfolder & "\" & fn)
Dim fs As New FileStream(destinationfolder & "\" & fn, FileMode.CreateNew)
fs.Write(binaryData, 0, binaryData.Length)
fs.Close()
Console.WriteLine("Recieved file: " & fn)
Else
Dim fs As New FileStream(destinationfolder & "\" & fn, FileMode.CreateNew)
fs.Write(binaryData, 0, binaryData.Length)
fs.Close()
Console.WriteLine("Recieved file: " & fn)
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End While
Catch ex2 As Exception
MsgBox(ex2.Message)
End Try
End Sub
End Class
Maybe pass the receiver part of the code into a new instance of a background worker?
That might allow each stream to come in on its own thread.
I haven't tried, but that was just the first thought that came to mind.

Variable names must be unique within a query batch or stored procedure

I'm trying to implement an asynchronous search "engine", but i'm facing some difficulties.
For some reason a SqlException is thrown every once in a while stating that:
"The variable name '#input' has already been declared. Variable names must be unique within a query batch or stored procedure."
Sample application
The following code targets the sys.messages table, so all you have to do is change the connection string.
Public Class Form1
Public Sub New()
Me.InitializeComponent()
Me.input = New TextBox() With {.Dock = DockStyle.Top, .TabIndex = 0}
Me.output = New RichTextBox() With {.Dock = DockStyle.Fill, .TabIndex = 1, .ReadOnly = True, .WordWrap = False}
Me.Controls.AddRange({Me.output, Me.input})
End Sub
Private Sub Search(sender As Object, e As EventArgs) Handles input.TextChanged
Dim input As String = Me.input.Text
Static command As SqlCommand
Static source As CancellationTokenSource
If (Not command Is Nothing) Then command.Cancel()
If (Not source Is Nothing) Then source.Cancel()
command = New SqlCommand()
source = New CancellationTokenSource()
Task.Factory.StartNew(Sub() Me.SearchingAsync(input, command, source.Token))
End Sub
Private Sub SearchingAsync(input As String, command As SqlCommand, token As CancellationToken)
Dim [error] As Exception = Nothing
Dim cancelled As Boolean = False
Dim result As List(Of sys_message) = Nothing
Try
Using connection As New SqlConnection("Server=instance\name;Database=name;Trusted_Connection=True;")
connection.Open()
command.Connection = connection
command.CommandType = CommandType.Text
command.CommandText = "select * from sys.messages where [text] like '%' + #input + '%';"
command.Parameters.AddWithValue("#input", input)
Using reader As SqlDataReader = command.ExecuteReader()
result = New List(Of sys_message)()
Do While (reader.Read() AndAlso (Not token.IsCancellationRequested))
result.Add(New sys_message() With {
.message_id = CInt(reader.Item("message_id")),
.language_id = CInt(reader.Item("language_id")),
.severity = CInt(reader.Item("severity")),
.is_event_logged = CBool(reader.Item("is_event_logged")),
.text = CStr(reader.Item("text"))
})
Loop
End Using
End Using
cancelled = token.IsCancellationRequested
Catch ex As SqlException When ex.Message.ToLower().Contains("operation cancelled by user")
cancelled = True
Catch ex As ThreadAbortException
cancelled = True
Catch ex As OperationCanceledException
cancelled = True
Catch ex As Exception
[error] = ex
Finally
Me.Invoke(
Sub()
'If (String.CompareOrdinal(input, Me.input.Text) = 0) Then
If (Not [error] Is Nothing) Then
Me.output.Text = String.Concat("Input='", input, "', Output={Result: 'error', Type: '", [error].GetType.Name, "', Message: '", [error].Message.Replace(Environment.NewLine, " "), "'}", Environment.NewLine, Me.output.Text).Trim()
ElseIf (cancelled) Then
Me.output.Text = String.Concat("Input='", input, "', Output={Result: 'cancelled'}", Environment.NewLine, Me.output.Text).Trim()
Else
Me.output.Text = String.Concat("Input='", input, "', Output={Result: 'success', Count: ", result.Count, "}", Environment.NewLine, Me.output.Text).Trim()
End If
'End If
End Sub
)
End Try
End Sub
Private WithEvents input As TextBox
Private WithEvents output As RichTextBox
Private Class sys_message
Public message_id As Integer
Public language_id As Integer
Public severity As Integer
Public is_event_logged As Boolean
Public text As String
End Class
End Class
Because you're inadvertently sharing SqlCommand objects between multiple calls to SearchingAsync. I'd remove the outer code that attempts to deal with trying to cancel those and just let SearchingAsync create its own, unshared instances.
At the same time, you might want to consider using the async API's that SqlCommand exposes, e.g. ExecuteReaderAsync which allow you to pass a cancellation token to them, so that cancellation is all handled by your single cancellation token.
You also need to ensure that the correct cancellation token is passed to the right invocation of your method:
Private Sub Search(sender As Object, e As EventArgs) Handles input.TextChanged
Dim input As String = Me.input.Text
Static source As CancellationTokenSource
If (Not source Is Nothing) Then source.Cancel()
source = New CancellationTokenSource()
Dim token = source.Token
Task.Factory.StartNew(Sub() Me.SearchingAsync(input, token))
End Sub
Basically, at this line of code:
Task.Factory.StartNew(Sub() Me.SearchingAsync(input, command, source.Token))
when it completes, all that you know is that, at some future point in time, it's going to run this:
Me.SearchingAsync(input, command, source.Token)
At that future point in time, it's going to load a SqlCommand object from the command variable and then invoke SearchingAsync (and, similarly, source is loaded at this point)
But, what if, in the meantime, your Search method has run again? It's cancelled the command and source that were originally intended for this method call, and it's replaced them with new copies. And it's scheduled another task to run SearchingAsync in the future. Those two calls end up referencing the same command objects and so it ends up with the #input parameter added to it twice.

Uploading to Google drive using VBA?

I have an MS Access database which now requires me to 'attach' documents to it. My intention is to store the documents on Google Drive and have a link on the database for users to retrieve the documents.
As there are many users spread through different cities, it is not practical to require them to have synced Google Drive folders. All the users will need the ability to upload to the database/GD so my intention is to have a separate Google account for the database - with its own login details.
example:
User clicks button to upload file
Save as dialog box appears and user selects file
Database logs into its Google Drive and uploads selected file
Lots of problems with this though, the main one being that Google Drive does not support VBA.
If the user is logged into their own Gmail account, that will probably be another issue.
I came across this code for vb.net on another site.
Imports System
Imports System.Diagnostics
Imports DotNetOpenAuth.OAuth2
Imports Google.Apis.Authentication.OAuth2
Imports Google.Apis.Authentication.OAuth2.DotNetOpenAuth
Imports Google.Apis.Drive.v2
Imports Google.Apis.Drive.v2.Data
Imports Google.Apis.Util
Imports Google.Apis.Services
Namespace GoogleDriveSamples
Class DriveCommandLineSample
Shared Sub Main(ByVal args As String)
Dim CLIENT_ID As [String] = "YOUR_CLIENT_ID"
Dim CLIENT_SECRET As [String] = "YOUR_CLIENT_SECRET"
'' Register the authenticator and create the service
Dim provider = New NativeApplicationClient(GoogleAuthenticationServer.Description, CLIENT_ID, CLIENT_SECRET)
Dim auth = New OAuth2Authenticator(Of NativeApplicationClient)(provider, GetAuthorization)
Dim service = New DriveService(New BaseClientService.Initializer() With { _
.Authenticator = auth _
})
Dim body As New File()
body.Title = "My document"
body.Description = "A test document"
body.MimeType = "text/plain"
Dim byteArray As Byte() = System.IO.File.ReadAllBytes("document.txt")
Dim stream As New System.IO.MemoryStream(byteArray)
Dim request As FilesResource.InsertMediaUpload = service.Files.Insert(body, stream, "text/plain")
request.Upload()
Dim file As File = request.ResponseBody
Console.WriteLine("File id: " + file.Id)
Console.WriteLine("Press Enter to end this process.")
Console.ReadLine()
End Sub
Private Shared Function GetAuthorization(ByVal arg As NativeApplicationClient) As IAuthorizationState
' Get the auth URL:
Dim state As IAuthorizationState = New AuthorizationState( New () {DriveService.Scopes.Drive.GetStringValue()})
state.Callback = New Uri(NativeApplicationClient.OutOfBandCallbackUrl)
Dim authUri As Uri = arg.RequestUserAuthorization(state)
' Request authorization from the user (by opening a browser window):
Process.Start(authUri.ToString())
Console.Write(" Authorization Code: ")
Dim authCode As String = Console.ReadLine()
Console.WriteLine()
' Retrieve the access token by using the authorization code:
Return arg.ProcessUserAuthorization(authCode, state)
End Function
End Class
End Namespace
It was suggested that the IE library could be utilised to log into the Google Drive and the API calls made from the above to upload. I don't know how to do this. Somewhere else it was mentioned that a 'COM wrapper' may be suitable. I don't have experience with any coding other than VBA (self taught) so am struggling to understand what the next step should be.
If anyone has done something similar or can offer any advice, I would be grateful to hear from you.
This thread might be dead now but if you are working with forms in your database and the user needs to be attaching the files to a particular record displayed in a form with a unique identification number then this is definitely possible but you would have to do it in an external application written in .NET I can provide you with the necessary code to get you started, vb.net is very similar to VBA.
What you would need to do is create a windows form project and add references to Microsoft access core dll and download the nugget package for google drive api from nugget.
Imports Google
Imports Google.Apis.Services
Imports Google.Apis.Drive.v2
Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Drive.v2.Data
Imports System.Threading
Public Class GoogleDriveAuth
Public Shared Function GetAuthentication() As DriveService
Dim ClientIDString As String = "Your Client ID"
Dim ClientSecretString As String = "Your Client Secret"
Dim ApplicationNameString As String = "Your Application Name"
Dim secrets = New ClientSecrets()
secrets.ClientId = ClientIDString
secrets.ClientSecret = ClientSecretString
Dim scope = New List(Of String)
scope.Add(DriveService.Scope.Drive)
Dim credential = GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, scope, "user", CancellationToken.None).Result()
Dim initializer = New BaseClientService.Initializer
initializer.HttpClientInitializer = credential
initializer.ApplicationName = ApplicationNameString
Dim Service = New DriveService(initializer)
Return Service
End Function
End Class
This code will authorise your drive service then you create a Public Shared Service As DriveService under your imports that can be used from any sub or function then call this function on your form load event like
Service = GoogleDriveAuth.GetAuthentication
Add a reference to your project to Microsoft Access 12.0 Object Library or whatever version you have
Then this piece of code will look at the form you want to get the value of the record no from and upload a file to your choice of folder
Private Sub UploadAttachments()
Dim NumberExtracted As String
Dim oAccess As Microsoft.Office.Interop.Access.Application = Nothing
Dim connectedToAccess As Boolean = False
Dim SelectedFolderIdent As String = "Your Upload Folder ID"
Dim CreatedFolderIdent As String
Dim tryToConnect As Boolean = True
Dim oForm As Microsoft.Office.Interop.Access.Form
Dim oCtls As Microsoft.Office.Interop.Access.Controls
Dim oCtl As Microsoft.Office.Interop.Access.Control
Dim sForm As String 'name of form to show
sForm = "Your Form Name"
Try
While tryToConnect
Try
' See if can connect to a running Access instance
oAccess = CType(Marshal.GetActiveObject("Access.Application"), Microsoft.Office.Interop.Access.Application)
connectedToAccess = True
Catch ex As Exception
Try
' If couldn't connect to running instance of Access try to start a running Access instance And get an updated version of the database
oAccess = CType(CreateObject("Access.Application"), Microsoft.Office.Interop.Access.Application)
oAccess.Visible = True
oAccess.OpenCurrentDatabase("Your Database Path", False)
connectedToAccess = True
Catch ex2 As Exception
Dim res As DialogResult = MessageBox.Show("COULD NOT CONNECT TO OR START THE DATABASE" & vbNewLine & ex2.Message, "Warning", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Warning)
If res = System.Windows.Forms.DialogResult.Abort Then
Exit Sub
End If
If res = System.Windows.Forms.DialogResult.Ignore Then
tryToConnect = False
End If
End Try
End Try
' We have connected successfully; stop trying
tryToConnect = False
End While
' Start a new instance of Access for Automation:
' Make sure Access is visible:
If Not oAccess.Visible Then oAccess.Visible = True
' For Each oForm In oAccess.Forms
' oAccess.DoCmd.Close(ObjectType:=Microsoft.Office.Interop.Access.AcObjectType.acForm, ObjectName:=oForm.Name, Save:=Microsoft.Office.Interop.Access.AcCloseSave.acSaveNo)
' Next
' If Not oForm Is Nothing Then
' System.Runtime.InteropServices.Marshal.ReleaseComObject(oForm)
' End If
' oForm = Nothing
' Select the form name in the database window and give focus
' to the database window:
' oAccess.DoCmd.SelectObject(ObjectType:=Microsoft.Office.Interop.Access.AcObjectType.acForm, ObjectName:=sForm, InDatabaseWindow:=True)
' Show the form:
' oAccess.DoCmd.OpenForm(FormName:=sForm, View:=Microsoft.Office.Interop.Access.AcFormView.acNormal)
' Use Controls collection to edit the form:
oForm = oAccess.Forms(sForm)
oCtls = oForm.Controls
oCtl = oCtls.Item("The Name Of The Control Where The Id Number Is On The Form")
oCtl.Enabled = True
' oCtl.SetFocus()
NumberExtracted = oCtl.Value
System.Runtime.InteropServices.Marshal.ReleaseComObject(oCtl)
oCtl = Nothing
' Hide the Database Window:
' oAccess.DoCmd.SelectObject(ObjectType:=Microsoft.Office.Interop.Access.AcObjectType.acForm, ObjectName:=sForm, InDatabaseWindow:=True)
' oAccess.RunCommand(Command:=Microsoft.Office.Interop.Access.AcCommand.acCmdWindowHide)
' Set focus back to the form:
' oForm.SetFocus()
' Release Controls and Form objects:
System.Runtime.InteropServices.Marshal.ReleaseComObject(oCtls)
oCtls = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(oForm)
oForm = Nothing
' Release Application object and allow Access to be closed by user:
If Not oAccess.UserControl Then oAccess.UserControl = True
System.Runtime.InteropServices.Marshal.ReleaseComObject(oAccess)
oAccess = Nothing
If NumberExtracted = Nothing Then
MsgBox("The Number Could Not Be Obtained From The Form" & vbNewLine & vbNewLine & "Please Ensure You Have The Form Open Before Trying To Upload")
Exit Sub
End If
If CheckForDuplicateFolder(SelectedFolderIdent, NumberExtracted + " - ATC") = True Then
CreatedFolderIdent = GetCreatedFolderID(NumberExtracted + " - ATC", SelectedFolderIdent)
DriveFilePickerUploader(CreatedFolderIdent)
Else
CreateNewDriveFolder(NumberExtracted + " - ATC", SelectedFolderIdent)
CreatedFolderIdent = GetCreatedFolderID(NumberExtracted + " - ATC", SelectedFolderIdent)
DriveFilePickerUploader(CreatedFolderIdent)
End If
Catch EX As Exception
MsgBox("The Number Could Not Be Obtained From The Form" & vbNewLine & vbNewLine & "Please Ensure You Have The Form Open Before Trying To Upload" & vbNewLine & vbNewLine & EX.Message)
Exit Sub
Finally
If Not oCtls Is Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(oCtls)
oCtls = Nothing
End If
If Not oForm Is Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(oForm)
oForm = Nothing
End If
If Not oAccess Is Nothing Then
System.Runtime.InteropServices.Marshal.ReleaseComObject(oAccess)
oAccess = Nothing
End If
End Try
End
End Sub
Check For Duplicate Folders In The Destination Upload Folder
Public Function CheckForDuplicateFolder(ByVal FolderID As String, ByVal NewFolderNameToCheck As String) As Boolean
Dim ResultToReturn As Boolean = False
Try
Dim request = Service.Files.List()
Dim requeststring As String = ("'" & FolderID & "' in parents And mimeType='application/vnd.google-apps.folder' And trashed=false")
request.Q = requeststring
Dim FileList = request.Execute()
For Each File In FileList.Items
If File.Title = NewFolderNameToCheck Then
ResultToReturn = True
End If
Next
Catch EX As Exception
MsgBox("THERE HAS BEEN AN ERROR" & EX.Message)
End Try
Return ResultToReturn
End Function
Create New Drive Folder
Public Sub CreateNewDriveFolder(ByVal DirectoryName As String, ByVal ParentFolder As String)
Try
Dim body1 = New Google.Apis.Drive.v2.Data.File
body1.Title = DirectoryName
body1.Description = "Created By Automation"
body1.MimeType = "application/vnd.google-apps.folder"
body1.Parents = New List(Of ParentReference)() From {New ParentReference() With {.Id = ParentFolder}}
Dim file1 As Google.Apis.Drive.v2.Data.File = Service.Files.Insert(body1).Execute()
Catch EX As Exception
MsgBox("THERE HAS BEEN AN ERROR" & EX.Message)
End Try
End Sub
Get The Created Folder ID
Public Function GetCreatedFolderID(ByVal FolderName As String, ByVal FolderID As String) As String
Dim ParentFolder As String
Try
Dim request = Service.Files.List()
Dim requeststring As String = ("'" & FolderID & "' in parents And mimeType='application/vnd.google-apps.folder' And title='" & FolderName & "' And trashed=false")
request.Q = requeststring
Dim Parent = request.Execute()
ParentFolder = (Parent.Items(0).Id)
Catch EX As Exception
MsgBox("THERE HAS BEEN AN ERROR" & EX.Message)
End Try
Return ParentFolder
End Function
Drive File Picker Uploader To Upload Files Selected From A File Dialog Box To The Newly Created Folder
Public Sub DriveFilePickerUploader(ByVal ParentFolderID As String)
Try
ProgressBar1.Value = 0
Dim MimeTypeToUse As String
Dim dr As DialogResult = Me.OpenFileDialog1.ShowDialog()
If (dr = System.Windows.Forms.DialogResult.OK) Then
Dim file As String
Else : Exit Sub
End If
Dim i As Integer = 0
For Each file In OpenFileDialog1.FileNames
MimeTypeToUse = GetMimeType(file)
Dim filetitle As String = (OpenFileDialog1.SafeFileNames(i))
Dim body2 = New Google.Apis.Drive.v2.Data.File
body2.Title = filetitle
body2.Description = "J-T Auto File Uploader"
body2.MimeType = MimeTypeToUse
body2.Parents = New List(Of ParentReference)() From {New ParentReference() With {.Id = ParentFolderID}}
Dim byteArray = System.IO.File.ReadAllBytes(file)
Dim stream = New System.IO.MemoryStream(byteArray)
Dim request2 = Service.Files.Insert(body2, stream, MimeTypeToUse)
request2.Upload()
Next
Catch EX As Exception
MsgBox("THERE HAS BEEN AN ERROR" & EX.Message)
End Try
End Sub
Get The Mime Type Of The Files Being Uploaded
Public Shared Function GetMimeType(ByVal file As String) As String
Dim mime As String = Nothing
Dim MaxContent As Integer = CInt(New FileInfo(file).Length)
If MaxContent > 4096 Then
MaxContent = 4096
End If
Dim fs As New FileStream(file, FileMode.Open)
Dim buf(MaxContent) As Byte
fs.Read(buf, 0, MaxContent)
fs.Close()
Dim result As Integer = FindMimeFromData(IntPtr.Zero, file, buf, MaxContent, Nothing, 0, mime, 0)
Return mime
End Function
<DllImport("urlmon.dll", CharSet:=CharSet.Auto)> _
Private Shared Function FindMimeFromData( _
ByVal pBC As IntPtr, _
<MarshalAs(UnmanagedType.LPWStr)> _
ByVal pwzUrl As String, _
<MarshalAs(UnmanagedType.LPArray, ArraySubType:=UnmanagedType.I1, SizeParamIndex:=3)> ByVal _
pBuffer As Byte(), _
ByVal cbSize As Integer, _
<MarshalAs(UnmanagedType.LPWStr)> _
ByVal pwzMimeProposed As String, _
ByVal dwMimeFlags As Integer, _
<MarshalAs(UnmanagedType.LPWStr)> _
ByRef ppwzMimeOut As String, _
ByVal dwReserved As Integer) As Integer
End Function
Hopefully this helps you make a start I am 100% convinced this is achievable as I have already done this for my manager.
This reply might be late but just wanna share one of the approach!
I have done this successfully with VBA and the demo link is here
http://www.sfdp.net/thuthuataccess/demo/democAuth.rar?attredirects=0&d=1
With this, you can upload, download or delete a file with your GoogleDrive in Access..
Just Wininet + WinHTTP enough
Dang Dinh ngoc
Vietnam

How do I send a gmail email in vb.net?

I want to send an email, but it gives me an error.
I have this code:
Sub sendMail(ByVal title As String, ByVal content As String)
Dim SmtpServer As New SmtpClient("smtp.gmail.com", 25)
SmtpServer.Credentials = New Net.NetworkCredential("name#gmail.com", "password")
Dim mail As New MailMessage("name#gmail.com", "name#gmail.com", title, content)
SmtpServer.Send(mail)
End Sub
I have a try catch which tries to call this method, it doesnt work so the catch runs and i get thes exception: System.Net.Mail.SmtpException: The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.0 Must issue a STARTTLS command first. b6sm3176487lae.0 - gsmtp Why do I get this error? and how do I fix it?
Gmail uses SMTP over SSL on port 465.
Try doing:
Dim SmtpServer As New SmtpClient("smtp.gmail.com", 465)
...
SmtpServer.EnableSsl = True
...
Try this - I know it works.
Dim Mail As New MailMessage
Dim SMTP As New SmtpClient("smtp.gmail.com")
Mail.Subject = "Security Update"
Mail.From = New MailAddress("name#gmail.com")
SMTP.Credentials = New System.Net.NetworkCredential("name#gmail.com", "password") '<-- Password Here
Mail.To.Add(address & "#gmail.com") 'I used ByVal here for address
Mail.Body = "" 'Message Here
SMTP.EnableSsl = True
SMTP.Port = "587"
SMTP.Send(Mail)
There is some problem with google account, you need to switch off some security settings. After sending email over and over, I received email on one of my support account (for google), the email were:
You recently changed your security settings so that your Google Account [trdjoko#gmail.com] is no longer protected by modern security standards.
If you did not make this change
Please review your Account Activity page at https://security.google.com/settings/security/activity to see if anything looks suspicious. Whoever made the change knows your password; we recommend that you change it right away.
If you made this change
Please be aware that it is now easier for an attacker to break into your account. You can make your account safer again by undoing this change at https://www.google.com/settings/security/lesssecureapps then switching to apps made by Google such as Gmail to access your account.
Sincerely,
The Google Accounts team
So I switched of additional security and i worked fine.
Change the port to 587. Port 25 does not support SSL.
A super easy way of doing this(without changing any security settings) is by using IFTTT and my IFTTT Maker.net libary
First, in IFTTT create a new recipe that's triggered by the Maker channel and name the event "send_gmail".
Then, select the Gmail engine and click "Send an email", and replace To with {{value1}}, subject with {{value2}} and message/body with {{value3}}
After that, in Visual studio, add ifttt.vb to your project. Now for the code:
Try
makechannel.scode = "your account ID"
makechannel.fireevent("send_gmail", "TO", "SUBJECT", "MESSAGE")
'code goes here if done
Catch ex As Exception
'code goes here if it fails
End Try
Then fill in your account ID. You can find it at ifttt.com/maker
And that's it!
I Have written the class which can perform this task easyly.
Imports System.Net.Mail
Public Class GGSMTP_GMAIL
Dim Temp_GmailAccount As String
Dim Temp_GmailPassword As String
Dim Temp_SMTPSERVER As String
Dim Temp_ServerPort As Int32
Dim Temp_ErrorText As String = ""
Dim Temp_EnableSSl As Boolean = True
Public ReadOnly Property ErrorText() As String
Get
Return Temp_ErrorText
End Get
End Property
Public Property EnableSSL() As Boolean
Get
Return Temp_EnableSSl
End Get
Set(ByVal value As Boolean)
Temp_EnableSSl = value
End Set
End Property
Public Property GmailAccount() As String
Get
Return Temp_GmailAccount
End Get
Set(ByVal value As String)
Temp_GmailAccount = value
End Set
End Property
Public Property GmailPassword() As String
Get
Return Temp_GmailPassword
End Get
Set(ByVal value As String)
Temp_GmailPassword = value
End Set
End Property
Public Property SMTPSERVER() As String
Get
Return Temp_SMTPSERVER
End Get
Set(ByVal value As String)
Temp_SMTPSERVER = value
End Set
End Property
Public Property ServerPort() As Int32
Get
Return Temp_ServerPort
End Get
Set(ByVal value As Int32)
Temp_ServerPort = value
End Set
End Property
Public Sub New(ByVal GmailAccount As String, ByVal GmailPassword As String, Optional ByVal SMTPSERVER As String = "smtp.gmail.com", Optional ByVal ServerPort As Int32 = 587, Optional ByVal EnableSSl As Boolean = True)
Temp_GmailAccount = GmailAccount
Temp_GmailPassword = GmailPassword
Temp_SMTPSERVER = SMTPSERVER
Temp_ServerPort = ServerPort
Temp_EnableSSl = EnableSSl
End Sub
Public Function SendMail(ByVal ToAddressies As String(), ByVal Subject As String, ByVal BodyText As String, Optional ByVal AttachedFiles As String() = Nothing) As Boolean
Temp_ErrorText = ""
Dim Mail As New MailMessage
Dim SMTP As New SmtpClient(Temp_SMTPSERVER)
Mail.Subject = Subject
Mail.From = New MailAddress(Temp_GmailAccount)
SMTP.Credentials = New System.Net.NetworkCredential(Temp_GmailAccount, Temp_GmailPassword) '<-- Password Here
Mail.To.Clear()
For i As Int16 = 0 To ToAddressies.Length - 1
Mail.To.Add(ToAddressies(i))
Next i
Mail.Body = BodyText
Mail.Attachments.Clear()
If AttachedFiles IsNot Nothing Then
For i As Int16 = 0 To AttachedFiles.Length - 1
Mail.Attachments.Add(New Attachment(AttachedFiles(i)))
Next
End If
SMTP.EnableSsl = Temp_EnableSSl
SMTP.Port = Temp_ServerPort
Try
SMTP.Send(Mail)
Return True
Catch ex As Exception
Me.Temp_ErrorText = ex.Message.ToString
Return False
End Try
End Function
End Class
Its the way, how to use class:
Dim GGmail As New GGSMTP_GMAIL("MyFromAddress1#gmail.com", "AccPassword", )
Dim ToAddressies As String() = {"ToAddress1#gmail.com", "ToAddress2#gmail.com"}
Dim attachs() As String = {"d:\temp_Excell226.xlsx", "d:\temp_Excell224.xlsx", "d:\temp_Excell225.xlsx"}
Dim subject As String = "My TestSubject"
Dim body As String = "My text goes here ...."
Dim result As Boolean = GGmail.SendMail(ToAddressies, subject, body, attachs)
If result Then
MsgBox("mails sended successfully", MsgBoxStyle.Information)
Else
MsgBox(GGmail.ErrorText, MsgBoxStyle.Critical)
End If
Hope this helps. Good coding

VBNET smtp retry send failed email address

hello fellow :) i am having a trouble on how can i retry sending failed email recipients. i am trying to make an application in vbnet where i can send emails to multiple address.
some code snippet:
Dim SmtpServer As New SmtpClient()
SmtpServer.Credentials = New Net.NetworkCredential(xInformation(0), xInformation(1))
SmtpServer.Port = CInt(xInformation(2))
SmtpServer.Host = xInformation(3)
SmtpServer.EnableSsl = True
Dim mail As New MailMessage()
mail = New MailMessage
mail.From = New MailAddress(xInformation(4), "Display Name")
mail.CC.Add(xInformation(5)) ' i will make a loop here to add recipients
mail.Subject = xInformation(6)
mail.IsBodyHtml = True
mail.Body = xInformation(7)
SmtpServer.Send(mail)
question arises:
1.) if i have to send, for instance, email to 5 recipients, and only
3 emails have been successfully sent, how can i know the
failed email addresses?
2.) where is the failed email address stored?
3.) what exceptions are needed to trapped this error?
I don't think you can catch these exceptions in your code, the emails that do not get sent you will want to check on the smtp server there should be a mail folder within inetpub
\\ServerName\c$\Inetpub\mailroot
Inside of this folder you should find a folder called: BadMail and Drop please look at the contents of these. Your VB code doesn't have access to what a valid email address might be, only that it will try to send an smtp email message, if it fails then the SMTP application handles that.
Per your comment:
Imports System.Net.Mail
Imports System.Threading
Imports System.Web.Configuration
''' <summary>
''' Provides a method for sending email.
''' </summary>
Public NotInheritable Class Email
Private Sub New()
End Sub
''' <summary>
''' Constructs and sends an email message.
''' </summary>
''' <param name="fromName">The display name of the person the email is from.</param>
''' <param name="fromEmail">The email address of the person the email is from.</param>
''' <param name="subject">The subject of the email.</param>
''' <param name="body">The body of the email.</param>
Public Shared Sub Send(fromName As String, fromEmail As String, subject As String, body As String)
Dim message As New MailMessage() With { _
Key .IsBodyHtml = False, _
Key .From = New MailAddress(fromEmail, fromName), _
Key .Subject = subject, _
Key .Body = body _
}
message.[To].Add(WebConfigurationManager.AppSettings("mailToAddresses"))
Dim originalRecipientCount As Integer = message.[To].Count
Dim failOnAnyAddress As Boolean = Convert.ToBoolean(WebConfigurationManager.AppSettings("failOnAnyAddress"))
Try
Send(message)
Catch generatedExceptionName As SmtpFailedRecipientException
If message.[To].Count = originalRecipientCount Then
' all recipients failed
Throw
End If
If failOnAnyAddress Then
' some (not ALL) recipients failed
Throw
End If
End Try
End Sub
Private Shared Sub Send(message As MailMessage)
Dim client As New SmtpClient()
Try
client.Send(message)
Catch ex As SmtpFailedRecipientsException
' multiple fail
message.[To].Clear()
For Each sfrEx As SmtpFailedRecipientException In ex.InnerExceptions
CheckStatusAndReaddress(message, sfrEx)
Next
If message.[To].Count > 0 Then
' wait 5 seconds, try a second time
Thread.Sleep(5000)
client.Send(message)
Else
Throw
End If
Catch ex As SmtpFailedRecipientException
' single fail
message.[To].Clear()
CheckStatusAndReaddress(message, ex)
If message.[To].Count > 0 Then
' wait 5 seconds, try a second time
Thread.Sleep(5000)
client.Send(message)
Else
Throw
End If
Finally
message.Dispose()
End Try
End Sub
Private Shared Sub CheckStatusAndReaddress(message As MailMessage, exception As SmtpFailedRecipientException)
Dim statusCode As SmtpStatusCode = exception.StatusCode
If statusCode = SmtpStatusCode.MailboxBusy OrElse statusCode = SmtpStatusCode.MailboxUnavailable OrElse statusCode = SmtpStatusCode.TransactionFailed Then
message.[To].Add(exception.FailedRecipient)
End If
End Sub
End Class
Convert any code from C# to vb.net: http://www.developerfusion.com/tools/convert/csharp-to-vb/