Access DB Query for Image Attachment File [duplicate] - ms-access

We are working on a project where we need to migrate data stored in an Access database to a cache database. The Access database contains columns with a data type of Attachment; some of the tuples contain multiple attachments. I am able to obtain the filenames of these files by using .FileName, but I'm unsure how to determine when one file ends and another starts in .FileData.
I am using the following to obtain this data:
System.Data.OleDb.OleDbCommand command= new System.Data.OleDb.OleDbCommand();
command.CommandText = "select [Sheet1].[pdf].FileData,* from [Sheet1]";
command.Connection = conn;
System.Data.OleDb.OleDbDataReader rdr = command.ExecuteReader();

(My original answer to this question was misleading. It worked okay for PDF files that were subsequently opened with Adobe Reader, but it did not always work properly for other types of files. The following is the corrected version.)
Unfortunately we cannot directly retrieve the contents of a file in an Access Attachment field using OleDb. The Access Database Engine prepends some metadata to the binary contents of the file, and that metadata is included if we retrieve the .FileData via OleDb.
To illustrate, a document named "Document1.pdf" is saved to an Attachment field using the Access UI. The beginning of that PDF file looks like this:
If we use the following code to try and extract the PDF file to disk
using (OleDbCommand cmd = new OleDbCommand())
{
cmd.Connection = con;
cmd.CommandText =
"SELECT Attachments.FileData " +
"FROM AttachTest " +
"WHERE Attachments.FileName='Document1.pdf'";
using (OleDbDataReader rdr = cmd.ExecuteReader())
{
rdr.Read();
byte[] fileData = (byte[])rdr[0];
using (var fs = new FileStream(
#"C:\Users\Gord\Desktop\FromFileData.pdf",
FileMode.Create, FileAccess.Write))
{
fs.Write(fileData, 0, fileData.Length);
fs.Close();
}
}
}
then the resulting file will include the metadata at the beginning of the file (20 bytes in this case)
Adobe Reader is able to open this file because it is robust enough to ignore any "junk" that may appear in the file before the '%PDF-1.4' signature. Unfortunately not all file formats and applications are so forgiving of extraneous bytes at the beginning of the file.
The only Officialâ„¢ way of extracting files from an Attachment field in Access is to use the .SaveToFile method of an ACE DAO Field2 object, like so:
// required COM reference: Microsoft Office 14.0 Access Database Engine Object Library
//
// using Microsoft.Office.Interop.Access.Dao; ...
var dbe = new DBEngine();
Database db = dbe.OpenDatabase(#"C:\Users\Public\Database1.accdb");
Recordset rstMain = db.OpenRecordset(
"SELECT Attachments FROM AttachTest WHERE ID=1",
RecordsetTypeEnum.dbOpenSnapshot);
Recordset2 rstAttach = rstMain.Fields["Attachments"].Value;
while ((!"Document1.pdf".Equals(rstAttach.Fields["FileName"].Value)) && (!rstAttach.EOF))
{
rstAttach.MoveNext();
}
if (rstAttach.EOF)
{
Console.WriteLine("Not found.");
}
else
{
Field2 fld = (Field2)rstAttach.Fields["FileData"];
fld.SaveToFile(#"C:\Users\Gord\Desktop\FromSaveToFile.pdf");
}
db.Close();
Note that if you try to use the .Value of the Field2 object you will still get the metadata at the beginning of the byte sequence; the .SaveToFile process is what strips it out.

It took me a while to piece together information to retrieve a file stored from within the attachment field so I just thought I'd share it.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb;
using System.IO;
using System.Diagnostics;
namespace AttachCheck
{
public partial class Form1 : Form
{
DataSet Set1 = new DataSet();
int ColId;
public Form1()
{
InitializeComponent();
OleDbConnection connect = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source='db/Adb.accdb'"); //set up connection
//CL_ID is a fk so attachments can be linked to users
OleDbCommand sql = new OleDbCommand("SELECT at_ID, [at_Name].[FileData], [at_Name].[FileName], [at_Name].[FileType] FROM Attachments WHERE at_ID =1;", connect);
//adding sql to addapter to be ran
OleDbDataAdapter OleDA = new OleDbDataAdapter(sql);
//attempting to open connection
try { connect.Open(); }
catch (Exception err) { System.Console.WriteLine(err); }
OleDA.Fill(Set1); //create and fill dataset
connect.Close();for (int i = 0; i < Set1.Tables[0].Rows.Count; i++)
{
System.Console.WriteLine(Set1.Tables[0].Rows[i]["at_Name.FileName"].ToString() + "This is the file name");
// by using a datagrid it allows you to display the attachments and select which to open, the open should be a button.
dataGridView1.Rows.Add(new object[] { Set1.Tables[0].Rows[i]["at_ID"].ToString(), Set1.Tables[0].Rows[i]["at_Name.FileName"].ToString(), "Open" });
}
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
DataGridViewCell cell = (DataGridViewCell)
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];
System.Console.WriteLine(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex]);
string FullRow = dataGridView1.Rows[e.RowIndex].ToString(); //data retrieved from click on datagrid
//need to sub string to cut away row index and leave number
string SubRow = FullRow.Substring(24, 1); //cutting string down from position 24 for 1 character
System.Console.WriteLine(SubRow + " This is Row"); //
int RowId = int.Parse(SubRow); //turn row number from string into integer that can be used
string FullRow2 = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].ToString(); //data retrieved from click on datagrid
//need to sub string to cut away row index and leave number
string SubRow2 = FullRow2.Substring(37, 1); //cutting string down from position 24 for 1 character
System.Console.WriteLine(SubRow2 + " This is Column"); //
int ColId = int.Parse(SubRow2); //turn row number from string into integer that can be used
if (ColId == 2)
{
string fileName = Set1.Tables[0].Rows[RowId]["at_Name.FileName"].ToString(); //assign the file to variable
//retrieving the file contents from the database as an array of bytes
byte[] fileContents = (byte[])Set1.Tables[0].Rows[RowId]["at_Name.FileData"];
fileContents = GetFileContents(fileContents); //send filecontents array to be decrypted
string fileType = Set1.Tables[0].Rows[RowId]["at_Name.FileType"].ToString();
DisplayTempFile(fileName, fileContents, fileType); //forward the file type to display file contents
}
}
private const int CONTENT_START_INDEX_DATA_OFFSET = 0; //values used for decoding
private const int UNKNOWN_DATA_OFFSET = 4; //the files
private const int EXTENSION_LENGTH_DATA_OFFSET = 8; //storedw within the access database
private const int EXTENSION_DATA_OFFSET = 12; //and this one
private byte[] GetFileContents(byte[] fileContents)
{
int contentStartIndex = BitConverter.ToInt32(fileContents, CONTENT_START_INDEX_DATA_OFFSET);
//'The next four bytes represent a value whose meaning is unknown at this stage, although it may represent a Boolean value indicating whether the data is compressed or not.
int unknown = BitConverter.ToInt32(fileContents, UNKNOWN_DATA_OFFSET);
//'The next four bytes contain the the length, in characters, of the file extension.
int extensionLength = BitConverter.ToInt32(fileContents, EXTENSION_LENGTH_DATA_OFFSET);
//'The next field in the header is the file extension, not including a dot but including a null terminator.
//'Characters are Unicode so double the character count to get the byte count.
string extension = Encoding.Unicode.GetString(fileContents, EXTENSION_DATA_OFFSET, extensionLength * 2);
return fileContents.Skip(contentStartIndex).ToArray();
}
private void DisplayTempFile(string fileName, byte[] fileContents, string fileType)
{
// System.Console.WriteLine(fileName + "File Name");
// System.Console.WriteLine(fileType + "File Type");
// System.Console.WriteLine(fileContents + "File Contents");
string tempFolderPath = Path.GetTempPath(); //creating a temperary path for file to be opened from
string tempFilePath = Path.Combine(tempFolderPath, fileName); // assigning the file to the path
if (!string.IsNullOrEmpty(tempFilePath)) //checking the temp file exists
{
tempFilePath = Path.Combine(tempFolderPath, //combines the strings 0 and 1 below
String.Format("{0}{1}",
Path.GetFileNameWithoutExtension(fileName), //0
Path.GetExtension(fileName))); //1
}
//System.Console.WriteLine(tempFolderPath + " tempFolderPath");
//System.Console.WriteLine(tempFilePath + " tempFilePath");
//'Save the file and open it.
File.WriteAllBytes(tempFilePath, fileContents);
//creates new file, writes bytes array to it then closes the file
//File.ReadAllBytes(tempFilePath);
//'Open the file.
System.Diagnostics.Process attachmentProcess = Process.Start(tempFilePath);
//chooses the program to open the file if available on the computer
}
}
}
Hope this helps someone

The following code goes through all the records of the Microsoft Access database data table and assigns each row to a recordset. The goes through all the attachments which are saved in field "Docs". Then extracts and saves those files on the disk.
This code is an extension on the code introduced by "Gord Thompson" above.
The only thing that I did was that I wrote the code for Visual Basic.NET.
Imports Microsoft.Office.Interop.Access.Dao
Put a reference to Dao by using the above line of code.
'Visual Basic.NET
Private Sub ReadAttachmentFiles()
'required COM reference: Microsoft Office 14.0 Access Database Engine Object Library
'define a new database engine and a new database
Dim dbe = New DBEngine
Dim db As Database = dbe.OpenDatabase("C:\Users\Meisam\Documents\Databases\myDatabase.accdb")
'define the main recordset object for each row
Dim rstMain As Recordset = db.OpenRecordset( _
"SELECT * FROM Companies", _
RecordsetTypeEnum.dbOpenSnapshot)
'evaluate whether the recordset is empty of records
If Not (rstMain.BOF And rstMain.EOF) Then
'if not empty, then move to the first record
rstMain.MoveFirst()
'do until the end of recordset is not reached
Do Until rstMain.EOF
Dim myID As Integer = -1
' ID is the name of primary field with uniqe values field
myID = CInt(rstMain.Fields("ID").Value)
'define the secondary recordset object for the attachment field "Docs"
Dim rstAttach As Recordset2 = rstMain.Fields("Docs").Value
'evaluate whether the recordset is empty of records
If Not (rstAttach.BOF And rstAttach.EOF) Then
'if not empty, then move to the first record
rstAttach.MoveFirst()
'do until the end of recordset is not reached
Do Until rstAttach.EOF
'get the filename for each attachment in the field "Docs"
Dim fileName As String = rstAttach.Fields("FileName").Value
Dim fld As Field2 = rstAttach.Fields("FileData")
fld.SaveToFile("C:\Users\Meisam\Documents\test\" & myID & "_" & fileName)
rstAttach.MoveNext()
Loop
End If
rstMain.MoveNext()
Loop
End If
'close the database
db.Close()
End Sub

According to Gord Thompson's answer I would like to provide the following information.
The first byte is the hexadecimal representation of the metadata's length. Byte 8 (0x04) is the hexadecimal representation of the length of the extension + 1. In this example this means that we need to remove the first 20 bytes (0x14):
This can be achieved very easily with the following functions:
Function SaveBinaryData(sFileName As String, ByteArray() As Byte)
Dim stream As New ADODB.stream 'Create Stream object
With stream
.type = adTypeBinary 'Specify stream type - we want To save binary data.
.Open 'Open the stream And write binary data To the object
.Write ByteArray
.SaveToFile sFileName, adSaveCreateOverWrite 'Save binary data To disk
End With
End Function
Public Function ReadBinaryData(sFileName As String) As Byte()
Dim stream As New ADODB.stream
With stream
.type = adTypeBinary
.Open
.LoadFromFile sFileName
ReadBinaryData = .Read
End With
End Function
Public Function ShiftL(arrBytes() As Byte, iShift As Integer) As Byte()
Dim i As Integer
Dim arrReturn() As Byte
For i = 0 To iShift - 1
ReDim Preserve arrReturn(i)
arrReturn(i) = Shift(arrBytes)
Next
ShiftL = arrReturn
End Function
Public Function Shift(arrBytes() As Byte) As Byte
Dim b As Long
If Not IsArray(arrBytes) Then
Err.Raise 13, , "Type Mismatch"
Exit Function
End If
Shift = arrBytes(0)
For b = 1 To UBound(arrBytes)
arrBytes(b - 1) = arrBytes(b)
Next b
ReDim Preserve arrBytes(UBound(arrBytes) - 1)
End Function
When you are accessing the value of the attachment field, just left shift the byte array by CDec(.Fields("FileData")(0)). After the shift you can process the file data as desired, e.g.:
Dim fldAttachment As DAO.Field2
Dim arrBytes() As Byte
Set fldAttachment = .Fields("FileData")
With fldAttachment
arrBytes = fldAttachment.value
ShiftL arrBytes, CDec(arrBytes(0))
SaveBinaryData .Fields("FileName").value, ByteArray
End With

Related

Create an XML file from SQL database and sent it to an API for further processing of data in VB .NET

Frequency should be 1 hour for creating an XML file. Once created, it needs to be sent through API. It has an API key for authenciation. It needs to be connected to a database first in order to get the data for creating the xml file. I need this functionality in VB (.NET)
Dim msgList As XElement
Dim xDoc As XDocument
Dim sw As New StringWriter()
Dim list As String = ""
Dim xmitList As String = ""
Dim xmitArray As New ArrayList
Dim xmlWriter As StringWriter = New StringWriter()
Dim SQLStatement As String = ""
Dim SQLErr As String = ""
Dim SQLResult As String = ""
Dim SQLResultTable As New DataTable
'********************
' Create the XML Document (XDeclaration sets the header information, and the XElement is the first node)
xDoc = New XDocument(
New XDeclaration("1.0", "UTF-16", "yes"),
New XElement("MessageList")
)
' Get the first node (<MessageList>) so we can then add child nodes to it when getting the data to send
msgList = xDoc.FirstNode
I came this far for creating the file in XML. Before this it needs to be connected to DB to grab the data and then start the process.
I tried creating the XML file but still stuck on completing that. Still left with two major steps excluding this, connecting to DB and sending the XML file using HTTP request. I need this functionality in VB (.NET).

How to save an Access OLE Object (BLOB) image to disk using VBA

So I seem to be able to save BLOB files from Access okay using the code below (which I found while searching how to export a BLOB). But it doesn't seem to be saving a valid .png file. When I try to open the file from disk I get the error "Windows Photo Viewer can't open this picture because the file is appears to be damaged, corrupted, or is too large. I know it's not too large because it's only 1.19MB. Is there a special way you have to write the BLOB file to disk that makes it readable or is there something else that I'm missing?
-EDIT-
Taking Gord's advice, I have got the code below using an ADODB.Stream. Unfortunately, I'm still running into the same problem where the file this writes to does not open in windows picture viewer. I'm wondering if this is because of the file extension I am giving it, but I've tried writing to a .JPG file (the default snipping tool save option which is where I expect the pictures to be input from) as well as .png (the file type I want) and .gif. Any ideas would be helpful as to how to solve this problem.
Public Sub TestBlobStream()
Dim mStream As New ADODB.Stream
Dim rs As RecordSet
Set rs = dbLocal.OpenRecordset("BlobTest")
Set mStream = New ADODB.Stream
mStream.Type = adTypeBinary
mStream.Open
mStream.Write rs("testBlob")
mStream.SetEOS
mStream.SaveToFile "D:\Target\TestPic.png", adSaveCreateOverWrite
mStream.Close
End Sub
-END EDIT-
Code referenced in original part of question:
Public Sub TestBlob()
Dim rs As RecordSet
Set rs = dbLocal.OpenRecordset("BlobTest")
DBug WriteBLOB(rs, "testBlob", "D:\Target\TestPic.png")
Set rs = Nothing
End Sub
Function WriteBLOB(T As DAO.RecordSet, sField As String, Destination As String)
Dim NumBlocks As Long, DestFile As Long, i As Long
Dim FileLength As Long, LeftOver As Long
Dim FileData As String
Dim RetVal As Variant
' Get the size of the field.
FileLength = T(sField).FieldSize()
If FileLength = 0 Then
WriteBLOB = 0
Exit Function
End If
' Calculate number of blocks to write and leftover bytes.
NumBlocks = FileLength \ BlockSize
LeftOver = FileLength Mod BlockSize
' Remove any existing destination file.
DestFile = FreeFile
Open Destination For Output As DestFile
Close DestFile
' Open the destination file.
Open Destination For Binary As DestFile
' SysCmd is used to manipulate the status bar meter.
RetVal = SysCmd(acSysCmdInitMeter, _
"Writing BLOB", FileLength / 1000)
' Write the leftover data to the output file.
FileData = T(sField).GetChunk(0, LeftOver)
Put DestFile, , FileData
' Update the status bar meter.
RetVal = SysCmd(acSysCmdUpdateMeter, LeftOver / 1000)
' Write the remaining blocks of data to the output file.
For i = 1 To NumBlocks
' Reads a chunk and writes it to output file.
FileData = T(sField).GetChunk((i - 1) * BlockSize + LeftOver, BlockSize)
Put DestFile, , FileData
RetVal = SysCmd(acSysCmdUpdateMeter, _
((i - 1) * BlockSize + LeftOver) / 1000)
Next i
' Terminates function
RetVal = SysCmd(acSysCmdRemoveMeter)
Close DestFile
WriteBLOB = FileLength
Exit Function
End Function

lotus agent request_content how to separate fields

I have a lotus agent running with lotusscript. Form the browser I post form data to the webserver and I receive this data with the following lotusscript:request_method = doc.GetItemValue( "request_content" )(0)
But if I have a form with for example name and phonenumber. Then my agent receives this as name=bla&phonenumber=243525
How can i separate these fields actually and secondly how can I receive XML on this agent so that I can extract this and put in to a document. I googled a lot but still got no solutions.
The way you get the data differs if the client makes a GET or a POST.
If this is a get, all the parameters are in the url in a url format.
Many many ressource on the web will give you some code to parse this url and get name and value a simple search in goolge will bring : http://searchdomino.techtarget.com/tip/Parsing-URL-Parameters-with-Ease
I use generally the following code, which add in the document context the fields received on url or on post.
Dim s As NotesSession
Set s = New notessession
Set doc = s.documentcontext
Dim myQuerystring As String
If doc Is Nothing Then
logErrorEX "getting a call without document context ?!?","", doc,""
GoTo returnErr
End If
If doc.QUERY_STRING_DECODED(0)<>"" Then'it's a GET
myQuerystring = doc.QUERY_STRING_DECODED(0)
ElseIf doc.QUERY_STRING(0)<>"" Then
myQuerystring = doc.QUERY_STRING(0)
'decode it !
ElseIf doc.REQUEST_CONTENT(0)<>"" Then'it's a POST
myQuerystring = doc.REQUEST_CONTENT(0) ' WARNING this is for POST but you will have to decode !!!
'decode it !
Else
logErrorEX "getting a call with document context but without query_string?!?","", doc,""
GoTo returnErr
End if
Call ExplodeQueryString(myQuerystring, doc)
Private Sub ExplodeQueryString (QueryString As String,doc As NotesDocument )
Dim ArgsList As Variant
ArgsList = Split (QueryString, "&")
If IsArray(ArgsList) Then
debugString = debugString+"ArgsList is an array of " & UBound(ArgsList)
Else
debugString = debugString+"ArgsList is NOT an array ??? " & ArgsList
End if
Dim ArgKey As String
Dim ArgValue As String
ForAll Arg In ArgsList
If left$(Arg, 1)= "_" Or Left$(Arg, 1)= "%" Then
'ignore it
else
ArgKey = strleft(Arg, "=")
If ArgKey = "" Then
'ignore it?
else
ArgValue = strright$(Arg, "=")
' AgentArgs(ArgKey) = ArgValue
doc.Replaceitemvalue ArgKey, ArgValue
End If
End if
End ForAll
End Sub
I didn't declare some global variable like debugString to shorten in.
The format you are seeing is the convention used by all web browser software to encode field data from forms. You can use functions similar to the ExplodeQueryString function in the code posted by Emmanual to parse it. It looks to me like he is taking each "&name" portion and creating a NotesItem with that name and using it to store the value from the "=value" portion. You can do that, or you can use a List, or whatever best fits your requirements.
There is no rule against sending POST data in other formats without using the &name=value convention. It just requires agreement between whatever software is doing the sending and your software on the receiving side. If they want to send you XML in the POST data, that's fine. You can use standard XML parsing functions to deal with it. Notes comes with a NotesDOMParsesr class that you can use if you want. If you are running on Windows, you can use Microsoft.XMLDOM instead.
I wrote a class a while back that does exactly what you ask for. It splits the query string (or request content) into a list of values, with the name as the list tag.
http://blog.texasswede.com/free-code-class-to-read-url-name-value-pairs/
Here is the code (I usually put it in a script library called Class.URL):
%REM
Library Class.URL
Created Oct 9, 2014 by Karl-Henry Martinsson
Description: Lotusscript class to handle incoming URL (GET/POST).
%END REM
Option Public
Option Declare
%REM
Class URLData
Description: Class to handle URL data passed to web agent
%END REM
Class URLData
p_urldata List As String
%REM
Sub New()
Description: Create new instance of URL object from NotesDocument
%END REM
Public Sub New()
Dim session As New NotesSession
Dim webform As NotesDocument
Dim tmp As String
Dim tmparr As Variant
Dim tmparg As Variant
Dim i As Integer
'*** Get document context (in-memory NotesDocument)
Set webform = session.DocumentContext
'*** Get HTTP GET argument(s) after ?OpenAgent
tmp = FullTrim(StrRight(webform.GetItemValue("Query_String")(0),"&"))
If tmp = "" Then
'*** Get HTTP POST argument(s) after ?OpenAgent
tmp = FullTrim(StrRight(webform.GetItemValue("Request_Content")(0),"&"))
End If
'*** Separate name-value pairs from each other into array
tmparr = Split(tmp,"&")
'*** Loop through array, split each name-value/argument
For i = LBound(tmparr) To UBound(tmparr)
tmparg = Split(tmparr(i),"=")
p_urldata(LCase(tmparg(0))) = Decode(tmparg(1))
Next
End Sub
%REM
Function GetValue
Description: Get value for specified argument.
Returns a string containing the value.
%END REM
Public Function GetValue(argname As String) As String
If IsElement(p_urldata(LCase(argname))) Then
GetValue = p_urldata(LCase(argname))
Else
GetValue = ""
End If
End Function
%REM
Function IsValue
Description: Check if specified argument was passed in URL or not.
Returns boolean value (True or False).
%END REM
Public Function IsValue(argname As String) As Boolean
If IsElement(p_urldata(LCase(argname))) Then
IsValue = True
Else
IsValue = False
End If
End Function
'*** Private function for this class
'*** There is no good/complete URL decode function in Lotusscript
Private Function Decode(txt As String) As String
Dim tmp As Variant
Dim tmptxt As String
tmptxt = Replace(txt,"+"," ")
tmp = Evaluate(|#URLDecode("Domino";"| & tmptxt & |")|)
Decode = tmp(0)
End Function
End Class
And this is how you can use it:
Option Public
Option Declare
Use "Class.URL"
Sub Initialize
Dim url As URLData
'*** Create new URLData object
Set url = New URLData()
'*** MIME Header to tell browser what kind of data we will return
Print "content-type: text/html"
'*** Check reqired values for this agent
If url.IsValue("name")=False Then
Print "Missing argument 'name'."
Exit Sub
End If
'*** Process name argument
If url.GetValue("name")="" Then
Print "'Name' is empty."
Else
Print "Hello, " + url.GetValue("name") + "!"
End If
End Sub

Show image using function

I'm new to VB. NET so please bear with me. In the code below, I have a picture box in my main form and I want the selected query profile_picture to show in the picture box but I have no idea what the function should return
Public Sub ShowPicture(ByVal username As String)
user = username
Dim dsSearch As DataSet
ModuleQuery.Showpic(username)
Dim dSearch As Byte() = DirectCast(dr("Photo"), Byte())
Dim ms As New MemoryStream(dsSearch)
prof_pic.Image = Image.FromStream(ms)
End Sub
This is a module which includes all SELECT queries so that it won't be messy.
I want to call a function but I don't know what to return so that I can show the image
Public Function Showpic(ByVal user As String)
Dim FunctionErrorState As Boolean = False
Dim InsertError As Boolean = False
Dim CloseError As Boolean = False
Dim dsData As New DataSet
Dim bite As Byte()
Try
openDB()
'MyADOConnection.Open()
Dim myQuery As String = "SELECT profile_picture FROM coa.register WHERE username = '" & user & "'"
Dim myCommand As New MySql.Data.MySqlClient.MySqlCommand(myQuery)
dr = myCommand.ExecuteReader
bite = DirectCast(dr("Photo"), Byte())
Catch ex As MySql.Data.MySqlClient.MySqlException
InsertError = True
End Try
Try
MyADOConnection.Close()
Catch exclose As MySql.Data.MySqlClient.MySqlException
CloseError = True
End Try
If InsertError Then
FunctionErrorState = True
End If
Return bite 'I just put something random here since I don't know what to retun
End Function
It looks to me like the image is being stored as a byte array in the database. You (i guess correctly) read this array from the database with the command bite = DirectCast(dr("Photo"), Byte()) in your ShowPic function. A byte array is just a large blob of data in memory, that you later query with the MemoryStream.
Therefore your ShowPic function (which is more a GetPic function ;-) should return Byte()
Public Function Showpic(ByVal user As String) As Byte()
You should initialize bite with Nothing
Dim bite As Byte() = Nothing
That way if an error occurs, the array will be nothing and you can check for that.
In order to convert the byte array, that contains the raw image data into an image you correctly use a MemoryStream and the Image.FromStream method. I/O in .NET works in large portions with streams. They are just a way to continously feed data from some source. In this case the source is just the memory, in particular the Byte array you got from the database.
You however never use that Byte array. Assign the result of the ShowPic function to a variable, in order to use it:
Public Sub ShowPicture(ByVal username As String)
user = username
Dim ImageData As Byte() = ModuleQuery.Showpic(username)
If ImageData IsNot Nothing Then
Using ms As New MemoryStream(ImageData)
prof_pic.Image = Image.FromStream(ms)
End Using
Else
'Your function returned nothing, so an error occured.
'This is a very crude way of error handling, since you never
'see the error in the first place, which makes debugging a
'nightmare. There are better ways, out of scope of this answer.
MessageBox.Show("No image retrieved due to an error :(")
End If
End Sub
That way you retrieve the image data from the database (again, rename it to GetPic or GetImageData or something) in ShowPic and return its raw data to the ShowPicture method where you decode and show it.

LotusScript Function Doesn't Save Form Fields

Can anyone spot an obvious reason as to why my save function isn't saving the fields in my form? It saves the document, but the fields are empty when I open it up. The following code is what I'm using:
Public Sub co_loopNamesAndSaveDocs()
'Dim variables
Dim s As New NotesSession
Dim thisDatabase As NotesDatabase
Set thisDatabase = s.CurrentDatabase
Dim ws As New NotesUIWorkspace
Dim uidoc As NotesUIDocument
Set uidoc = ws.CurrentDocument
Dim currentDoc As NotesDocument
Set currentDoc = uidoc.Document
Dim newDoc As NotesDocument
Dim PersonNameField As NotesItem
Set PersonNameField = currentDoc.GetFirstItem("PersonName")
'Loop through values in PersonNameField and create a new document for each value found
Forall pName In PersonNameField.Values
Set newDoc = New NotesDocument (thisDatabase)
newDoc.Form="newLocationForm"
newDoc.StartDate = currentDoc.StartDate(0)
newDoc.EndDate = currentDoc.EndDate(0)
newDoc.Duration = currentDoc.Duration(0)
newDoc.StartTime = currentDoc.StartTime(0)
newDoc.EndTime = currentDoc.EndTime(0)
newDoc.Comments = currentDoc.Comments(0)
newDoc.Status = currentDoc.Status(0)
newDoc.LocationCode = currentDoc.LocationCode(0)
newDoc.PersonName = pName
Call newDoc.Save (True, False, False)
End Forall
End Sub
Thanks in advance.
Since I don't see an obvious error in the coding, I'd say that the fields in newDoc are blank because the fields in currentDoc are blank. And since currentDoc was set to uidoc.Document, that probably means that you have a synch problem between front-end and back-end documents. I.e., the values exist in your uidoc, but have not yet been saved to the back-end prior to calling this code. If I'm right, try calling uidoc.save() before assigning currentDoc. If you don't want to save to the back-end, then instead of using the back-end as your data source you should be using uidoc.fieldGetText("PersonName") and parsing out the values.