Saving Image as OLE Object, in Access - ms-access

I have a table with a field that is of type OLE Object. I then have a form with a number of fields. Some are just text fields. But, I also have an Image object on the form. When a user clicks a button, a dialog opens and they can pic a photo. Once they select the photo, the Image object displays that picture. I want to save that image to database. What I have only seems to save a reference to where the file is located, on the computer. So, this would not work if the db is moved. Here is the code I have:
Dim wrkCurrent As DAO.Workspace
Dim dbs As DAO.Database
Dim rstPerson As DAO.Recordset
Set wrkCurrent = DBEngine.Workspaces(0)
Set dbs = CurrentDb
Set rstPerson = dbs.OpenRecordset("SELECT * FROM tbl_person WHERE id =" & ID)
With rstPerson
.Edit
!bio_photo = Me.Image37.picture
.Update
End With
How would I save the image file to the OLE Field, so that I could load it back to the Image object, on the form, at a later time?
Thanks
Answer:
So, what I ended up doing was following this https://support.microsoft.com/en-us/kb/210486 [EDIT: that link is now dead, try this instead]
I use the readBLOB function to read the file and save it into the database. Then, when I run a report or open a form that has the picture, onload, I use the WriteBlob function to write the file to a temp folder and then use that path to populate an Image object.

Databases can grow to enormous sizes when you start embedding images, leading to slower queries, crashes, timeouts, and dissatisfied users. Use OLE with caution when adding images into a database
Simple Google search has how to load ole object from folder into table
And a search on this site comes up with auto attach images using vba

Related

Need to Change Linked Tables in MS Access DB with Username, Password and System DB

I have a front end DB, which needs to link to different back end DBs. To give you perspective, it relates to stand alone MDB files. The software in question builds a DB per company.
At the moment I am writing code within one of these MDB files.
For scalability I am now creating a new DB which will link to each MDB via code, and therefore my questions are as follows
How do I change the linked table location via code / VB so that the user can select the company / DB they want to work on
How do I do this with passing a username and password which is the same for all of the companies / DBs
And as per below we need to verify the username and password via the systemDB for it to open successfully.
As an FYI, this is how we open the DB on a standalone basis-
"C:\Program Files (x86)\Microsoft Office\root\Office16\MSACCESS.EXE" "C:\temp\SAMPLE.mdb" /WRKGRP "C:\ProgramData\SOFTWARE\SYSTEM.mdw" /user:username /pwd:password
This is not a problem at all and is absolutely able to be accomplished given the clarification that you are using a single MDW file.
To clarify Microsoft Access Workgroup Security is essentially a "session" security model that applies directly to the front-end MDB file as you open it.
Your example command line means that Microsoft Access will open the SAMPLE.MDB front-end file using the workgroup file you specified.
Once Microsoft Access has opened SAMPLE.MDB under that workgroup file, you cannot change to another workgroup file within that "session" without closing Microsoft Access and re-opening under the new workgroup file.
FYI - it IS possible to open via code, a table in another MDB using another workgroup file within that connection, but in this manner, the table is only usable in code as a RecordSet (for example), you can't make it a linked table.
Anyway, back to your real issue. How to link a different back-end set of tables for each Company.
My recommendation would be to add a few fields to your Company table that defines the filename and location of each back-end file. For example:
Notice that the location can be a UNC path, or a mapped drive path. Or maybe you don't need to define a location in the table explicitly. Maybe all of the back-ends are in the same folder, or in a definable dynamic location like \Dallas\Dallas.mdb, \NewYork\NewYork.mdb, etc. As long as you can determine the location of each back-end in some manner, then you are fine.
Now, since you will likely have "global" front-end tables, maybe also some "global" linked back-end tables i.e. Common.mdb, and your company-specific back-end tables, I would recommend having a front-end table that defines the name of each of the tables that is involved only in the company-specific files. That way, we can easily loop through just those table names and make the link changes.
For the linking code, let's say that you have prompted the User for which Company they want, and you pass the CompanyID to a re-linking function:
Public Function ChangeCompanyLinks(CompanyID As Long) As Boolean
Dim db As DAO.Database
Dim ldb As DAO.Database
Dim tdf As DAO.TableDef
Dim rstCompany As DAO.Recordset
Dim rstTables As DAO.Recordset
Dim mssql As String
Dim dbFullPath As String
Dim retVal As Boolean
Set db = CurrentDb()
retVal = False
mssql = "SELECT * FROM [tblCompany] WHERE [CompanyID] = " & CompanyID
Set rstCompany = db.OpenRecordset(mssql, dbOpenSnapshot)
If Not rstCompany.BOF Then
dbFullPath = rstCompany("DBLocation") & "\" & rstCompany("DBName")
If Dir(dbFullPath) = rstCompany("DBName") Then
'NOTE: By opening a temporary constant link to the back-end during
' relinking, the relinking runs faster
Set ldb = OpenDatabase(dbFullPath)
mssql = "SELECT * FROM [tblLinkedTables] WHERE [FileType] = ""Company"""
Set rstTables = db.OpenRecordset(mssql, dbOpenSnapshot)
Do While Not rstTables.EOF
Set tdf = db.TableDefs(rstTables("TableName"))
tdf.Connect = ";DATABASE=" & dbFullPath
tdf.RefreshLink
rstTables.MoveNext
Loop
rstTables.Close
ldb.Close
retVal = True
Else
MsgBox "Unable to Locate Company File"
End If
End If
rstCompany.Close
ChangeCompanyLinks = retVal
Set rstCompany = Nothing
Set rstTables = Nothing
Set ldb = Nothing
Set tdf = Nothing
db.Close
Set db = Nothing
End Function
Obviously you will want to add error handling, and customize this a bit to fit your situation, but this code will re-link the specified tables to a new back-end.
Please note that if you eventually change to have your back-end tables in SQL Server (which I highly recommend), the re-linking code would need to be modified a bit. See this answer for more details on that.

Access: display .vsd from attachments

I have an Access table where each item has attached a Visio file (.vsd).
In my Access form, I would like to see the file. I don't care if it is an editable Visio file, a preview or just an image.
I have built a VBA code that let me load the Visio file from a Directory. But I need to load the file from a table.
Here my VBA code.
Private Sub Carica_Dati()
Dim path As String
path = "C:\Users\VisioFlow_001.vsd"
With Me.VisioObject ' name of the OLE Object where I want to put the Visio file
.Class = "Visio.Drawing.11"
.OLETypeAllowed = acOLELinked
.SourceDoc = path ' HERE I WANT TO LOAD THE FILE FROM A TABLE OF THE DB
.Enabled = True
.Locked = False
.Action = acOLECreateLink
.SizeMode = acOLESizeZoom
End With
End Sub
Here a preview of the form.
UPDATE
Here a picture to show how the file is attached to the table.
Since attachment fields in Access aren't very consistent, directly loading them into an OLE object is not an option, unless you're willing to do sophisticated things
Microsofts documentation on attachments can be found here
My observations on attachments: the binary data field contains one of the following:
Some characters I can't identify + the file type + the file data appended to it
Some characters I can't identify + the file type + a compressed version of the file data appended to it
Microsoft, in all it's wisdom, has supplied us with a way to save the original file to the disk, but hasn't supplied us with a way to remove those initial characters and the file type from the actual file data, or an easy way to identify if the file is compressed or not (you can check the file type with the table supplied in the link to check if it should be).
In conclusion, you're probably off best either replacing your attachment field with an OLE object in the database, or writing the attachment files to disk before displaying them.
If you use an OLE object field, and load them in as long binary data (not through the GUI), you can easily achieve the behaviour you seek without writing the file to disk, since the binary data is available without any extra characters.
To write an attachment file to disk:
Dim rsForm As DAO.Recordset2
Dim rsFiles As DAO.Recordset2
Set rsForm = Me.Recordset
Set rsFiles = rsForm.Fields("attachment_column").Value
If Not rsFiles.EOF Then
Dim fileLocation As String
fileLocation = Environ("TEMP") & rsFiles.Fields("FileName").Value
rsFiles.Fields("FileData").SaveToFile fileLocation
'Your existing code to display the OLE object here
End If
You do not want to use the Attachment feature. Its purpose is different than what you are attempting.
Put the images into their own stand alone folder outside of the database.
In the table that holds the records for your main form - you need a new field which holds the path & image file name. This is a text field. (If the path segment is uniform for all one can insert that elsewhere via code rather than store it in this field.)
Then in form design - use the image control. This control (all controls) have a source property - that will change with each record using that field that holds the path & file name.
Do a bing/google on the topic of changing an image with every record - the set up isn't intuitive necessarily. Note that older editions did things differently so be sure you get relatively recent advice.
Then when you are using the form and change records - the image will change.
Note after having typed all this.... I have no idea if the visio file type works - I know that jpg and bmp do... so first sanity check a simple fixed image with that file type to see if it works ...

Why does my database object show no Recordsets?

Why does my database object show no Recordsets? And why does it not show a Connection? The key bit of code is:
Public Sub PrintRecords()
Dim dbCurr As DAO.Database
Set dbCurr = CurrentDb
Dim rsCourses as Recordset
Set rsCourses = CurrentDb.OpenRecordset(“Courses”)
End Sub
Here is my screenshot, where the database has tables (upper left), but the CurrentDB object has a name but no Recordsets (in the locals window below.)
For what it’s worth, this is in Access 2013, following this tutorial to manipulate the database, stopping on the error “Run-time error ‘3078’: The Microsoft Access database engine cannot find the input table or query”. But the problem seems to be deeper than that.
You have typographic quotes in there, use straight ones "".
And use your assigned database object:
Set rsCourses = dbCurr.OpenRecordset("Courses")
And please don't post only screenshots of code, copy & paste the code itself as text.

How do I create copies of CurrentDb using VBA

I need to create copies of the CurrentDB using VBA (approx. 12 copies). The copies need to be clones of the master database containing all the same forms, queries, etc. except only a limited dataset.
DoCmd.CopyDatabaseFile seems to be made for this, but only works if you are using it to copy the DB to an MS SQL Server. As MS states on their website:
Copies the database connected to the current project to a Microsoft
SQL Server database file for export.
docmd.TransferDatabase only exports the data itself, but not the structure, forms, etc.
Code I have found on the web and adapted doesn't work and throws an error on the .CopyFile line saying:
Run-time error 52: Bad file name or number
This is the code
Sub CopyDB()
Dim external_db As Object
Dim sDBsource As String
Dim sDBdest As String
sDBsource = "\\group\bsc\groups\L\BDTP\Compliance\ComplianceData\Compliance Group Reporting.accdb"
sDBdest = "\\group\bsc\groups\L\BDTP\Compliance\ComplianceData\Compliance Group Reporting_2.accdb"""
Set external_db = CreateObject("Scripting.FileSystemObject")
external_db.CopyFile sDBsource, sDBdest, True
Set external_db = Nothing
End Sub
How can I fix the above line? Alternatively is there a direct command in Access to create a copy? The "create backup" function would be tailor made for this, but I can not find it in VBA.
Looks like you have an extra quote in sDBdest accdb"""
And for database copy you can also use
FileCopy sDBsource, sDBdest
Instead of Scripting object

Creating a submit button on a registration form in Microsoft Access

I dont have much Access experience. I'm an intern at a database management company and my boss gave me a test project. He wants me to create a registration form with a submit button to enter some data into a table. I created the form, but how do I create a submit button that enters data into the table?
If you are using straight Microsoft Access - you could base a form on the table (I know, not a terribly great idea for those in the know - just keeping it simple), and as you enter information into the form, it enters it into each respective column of the record - no submission action necessary, when you reach the end of the record - the next new record with blank columns is given to you automatically for filling in.
Now, if you -really- need a form that works like they do on the internet - you'd have to create an unbound form - then create a 'Submit' button with VBA code that takes the text boxes you have on the form and inserts them into the table in your database, clearing your fields after submission to allow for the entry of your next record. You can even write up a 'Cancel' button that clears all of your fields to start again if you so desire.
I am sorry if I am being very general - but you haven't given us a lot to go on.
As the others have said the way to go here is an unbound form. Here is a generic code template I use when connecting to a JET database. Note the use of DAO over ADO as DAO is faster when talking to a JET data source
Dim db As DAO.Database
Dim rst As DAO.Recordset
Set db = DBEngine(0).OpenDatabase(strLinked_db_path)
Set rst = db.OpenRecordset("tblHours_lost", dbOpenTable)
With rst
.Addnew
!Hours_Lost = Me.txtHours_lost
!Type = Me.cboLoss_type
!do_not_deduct = Me.chkDo_not_deduct
!Notes = Me.txtNotes
!Start_time = Me.txtStart_time
.Update
End With
rst.Close
db.Close
Set rst = Nothing
Set db = Nothing
All you need to do is open the recordset and put the data in, its quite simple to do once you get the hang of it
You don't need to make a string date should be saved.
Microsoft access is designed to add in the properties from your form a table and then you can add a field and you don't have to make a Submit button the state should be saved, all strings will be done automatically by the system.
U need to create connection string which will provide path to to date
then create a command object then give the con object as parameter to command object along with command and execute it