I have been searching for a way to extract images from access forms. A search on Google will nearly always point to OLEtoDisk. This software allows to export images stored in OLE fields inside access tables. This is not what I want.
I have a form with some logos, headers and background images. Those images are making the database become bigger and bigger (because they are embedded in the form). I would extract them, place them on our server together with the back-end file and add them back to my forms but this time as linked images instead of embedded images.
I hope I am making myself clear. Any suggestions are welcome.
EDIT : Added the code I'm using to export an Image control's PictureData as an image file. This code doesn't work as intended. I found out that PictureData is a byte array but after copying it in a file, I get one NUL character every two characters.
Public Function savePict(pImage As Access.Image)
Dim fname As String 'The name of the file to save the picture to
Dim iFileNum As Double
fname = Environ("Temp") + "\temp.png" ' Destination file path
iFileNum = FreeFile 'The next free file from the file system
Open fname For Binary Access Write As iFileNum
Dim tbyte As Variant
Dim i As Double
'Write the byte array to the file
For i = 0 To Len(pImage.PictureData)
Put #iFileNum, , pImage.PictureData(i)
Next i
Close #iFileNum
End Function
The picture data is an EMF file, with a wrapper of 8 bytes.
This is your routine modified to use the correct file extension
Public Function savePict(pImage As Access.Image)
Dim fname As String 'The name of the file to save the picture to
Dim iFileNum As Double
Dim bArray() As Byte, cArray() As Byte
Dim lngRet As Long
fname = Environ("Temp") + "\temp.emf" ' Destination file path
iFileNum = FreeFile 'The next free file from the file system
' Resize to hold entire PictureData prop
ReDim bArray(LenB(pImage.PictureData) - 1)
' Resize to hold the EMF wrapped in the PictureData prop
ReDim cArray(LenB(pImage.PictureData) - (1 + 8))
' Copy to our array
bArray = pImage.PictureData
For lngRet = 8 To UBound(cArray)
cArray(lngRet - 8) = bArray(lngRet)
Next
Open fname For Binary Access Write As iFileNum
'Write the byte array to the file
Put #iFileNum, , cArray
Close #iFileNum
End Function
Finally here is the code that worked as intended : Export a PNG image from a form's Image control.
Public Function savePict(pImage As Access.Image)
Dim fname As String 'The name of the file to save the picture to
fname = Environ("Temp") + "\temp.png" ' Destination file path
Dim iFileNum As Double
iFileNum = FreeFile 'The next free file from the file system
Dim pngImage As String 'Stores the image data as a string
pngImage = StrConv(pImage.PictureData, vbUnicode) 'Convert the byte array to a string
'Writes the string to the file
Open fname For Binary Access Write As iFileNum
Put #iFileNum, , pngImage
Close #iFileNum
End Function
Take your form that has a background image or AutoFormat that you like
Right-click on the form in the Navigation Pane and select Export >> XML
On the first page of the wizard, select a destination to drop some files (Desktop is fine)
A small dialog will then appear with three check boxes
Select the first option (Data) and third option (Presentation) and then click OK
Click the Close button on the last page of the wizard after the export is complete
If you are looking to re-use the image in another access database (ie you lost the original image file, but want to use it elsewhere), a far easier method would be to import the object (form, report etc) into your new Access database using the External Data -> Access menu.
You can then just copy paste the image control where you want to use it...
Unfortunately copy/paste of image controls between Access databases doesnt work as you'd like.
Related
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 ...
I've been developing an "IDE" for custom software that relies on a web browser control to display it's information. The software uses an external file "common.vbs" to access common functions within it's web pages. Sprinkled throughout various web pages within the application is the html tag:
<script LANGUAGE="VBScript" src="common.vbs"></script>
In my application I've tried the following code after importing the code into a resource string:
Dim sPath As String = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache)
sPath = Path.Combine(sPath, "common.vbs")
Try
Dim fs As FileStream = File.Create(sPath)
Dim sData As String = My.Resources.common
Dim Info As Byte() = New UTF8Encoding(True).GetBytes(My.Resources.common)
fs.Write(Info, 0, Info.Length)
fs.Close()
Catch ex As Exception
MsgBox(ex.Message)
End Try
The code doesn't error. When I test (withing the same function) reading the file back, it's contents are returned; I know the file is being written, but when the any of the pages load with the above HTML tags, I get an error from the page:
An error has occurred in the script on this page
Line: 0
Char: 0
Error: Script error
Code: 0
URL: about:common.vbs
The file I'm trying to "include" contains only functions like:
Function DoHelp
window.external.DoHelp "", "", -1, -1
End Function
Function SQLDate( d)
SQLDate = "'" & DatePart("yyyy", d) & "-" & DatePart("m", d) & "-" & DatePart("d", d) & "'"
End Function
Function MonitorJob( jobId)
on error resume next
window.external.UIControl.MonitorJob jobId, 0
End Function
Within the application, there are no problems loading and using any of the functions contained within the file. The actual contents of the file is from the application and hasn't been edited in any manor. Any page that I load with my application that has the file included errors out, including simple test pages.
Does anyone have any ideas on how to get the web browsers control recognize a file from within a script's scr tag that's not part of the actual page being loaded and supplied from the hosting application? Editing all of the pages within the source application really isn't an option; may are dynamically created and there is a large number of them.
I've tried to include as much information as I can here, but if you need more info, please feel free to ask!
Thanks, Fred
EDIT / UPDATE:
I've tried writing all of the files I need to "include" into a temp folder, write the calling HTML file to the same folder, then load the web control using a file stream. The results are the same.
EDIT / UPDATE
I must have things wrong; Writing all of the "resource Files" into the temp folder, then writing the resulting HTML page into the same file and finally calling the Navigate method to that temp folder and file results in the page properly loading images and the underlying included VBS file.
Last EDIT / UPDATE
It took me a while to get all of the parts working correctly. Below is the answer that solved the issue.
Part of the problem is how the web control is loaded. Using the document methods circumvents accessing the file system because no base location is used. In order to access items in the file system, the "source page" needs to be in the file system. The next part of the problem was getting the resources into the file system. Below is the code that I used. Important note: for demonstration reasons only, the code for the Temp Path is located inside this routine. It actually resides out side the routine for access in other routines.
Sub UpdateFiles(sData)
'Write all the dependent files into the working folder.
Dim sLocalPath As String = Path.Combine(Path.GetTempPath, Guid.NewGuid.ToString)
Do While Directory.Exists(TempWorkingPath) Or File.Exists(TempWorkingPath)
sLocalPath = Path.Combine(Path.GetTempPath, Guid.NewGuid.ToString)
Loop
Directory.CreateDirectory(sLocalPath)
File.WriteAllBytes(Path.Combine(sLocalPath, "common.vbs"), System.Text.Encoding.UTF32.GetBytes(My.Resources.common))
Dim aImageList() As String = Split(My.Resources.M3ImageList, vbCrLf)
Dim sImageList As String = Replace(Join(Split(My.Resources.M3ImageList, vbCrLf), ","), "-", "_")
Dim ResourceSet As Resources.ResourceSet = My.Resources.ResourceManager.GetResourceSet(Globalization.CultureInfo.CurrentCulture, True, True)
For Each Dict As DictionaryEntry In ResourceSet.OfType(Of Object)()
If TypeOf (Dict.Value) Is Drawing.Image Then
If InStr(sImageList, Dict.Key, vbTextCompare) > 0 Then
Dim ImageConverter As New ImageConverter
Dim aBytes() As Byte = ImageConverter.ConvertTo(Dict.Value, GetType(Byte()))
Dim sName As String = Replace(Dict.Key.ToString & ".gif", "_", "-")
File.WriteAllBytes(Path.Combine(sLocalPath, sName), aBytes)
End If
End If
Next
File.WriteAllText(Path.Combine(sLocalPath, "index.html"), sData)
End Sub
I used a separate resource file that listed all of the files I needed to drive this routine. One point of note, when I imported all of the GIF's, the -'s were converted into _'s, thus the replace statements. I also used a filter (the Instr command) so that only the items in the list were exported.
I spent a lot of time on this, and I hope others will find it useful!
Fred
I have a form in Microsoft Access which lets users upload attachments to each record. I'd like to make it a little user friendly by letting users drag and drop files into the attachment field. What is the best way of doing this/how do I do this?
Drag and drop might be a bit more sophisticated, how about VBA code to manipulate what you wish to achieve? This article has a great reference to what you wish to do. http://www.access-freak.com/tutorials.html#Tutorial07
Here is a way to drag and drop "attached" files for use with MS Access database.
(Currently using Office 365 Version 1811)
MS Access currently allows drag and drop to a hyperlink field.
Using this capability this example allows drag and drop to store an attachment file to a storage location while keeping a link to the original and new locations. The event runs when a file is dropped into the HyperlinkIn box on the form or when the hyperlink is changed the normal way.
It is better to store the file in a storage location with a link than to store it within the .accdb file due to the 2GB limitation. You might call this a database + file server architecture. By using the record number and optionally the database and table name and attachment number you can ensure unique file names.
Make a Table and Form with 3 fields.
ID (AutoNumber)
HyperlInkIN (hyperlink)
HyperLinkOUT (hyperlink)
Insert this VBS code for AfterUpdate event for the HyperlinkIn form control.
Private Sub HyperlinkIN_AfterUpdate()
Dim InPath As String
Dim FileName As String
Dim OutFolder As String
Dim OutPath As String
Dim RecordNo As String
Dim FileExt As String
OutFolder = "\\networkdrive\vol1\attachments\" 'specify the output folder
InPath = Me!HyperlinkIN.Hyperlink.Address
RecordNo = Me!ID
If Len(InPath) > 0 Then
FileName = Right(InPath, Len(InPath) - InStrRev(InPath, "\")) 'get the file name
FileExt = Right(FileName, Len(FileName) - InStrRev(FileName, ".") + 1) ' get the file extension with dot
'build the new path with output folder path and record number and date and extension
OutPath = OutFolder & "Record " & RecordNo & " Attachment " & Format(Now(), "ddmmmyy") & FileExt
FileCopy InPath, OutPath
Me!HyperlinkOUT = "#" & OutPath & "#"
MsgBox "Copied file to archives " & vbCrLf & InPath & vbCrLf & OutPath
End If
End Sub
I am somewhat inexperienced with vba so there may be some better ways to ensure and verify a successful file copy but this example works for me and is easy for me to understand. I used the MsgBox to help debug with the actual file copy commented out.
Because this page comes as first when searching for "MS Access drag drop", I'm adding my part here. If you are after some cool UI, you can checkout my Github for sample database using .NET wrapper dll. Which allows you to simply call a function and to open filedialog with file-drag-and-drop function. Result is returned as a JSONArray string.
code can be simple as
Dim FilePaths As String
FilePaths = gDll.DLL.ShowDialogForFile("No multiple files allowed", False)
'Will return a JSONArray string.
'Multiple files can be opend by setting AllowMulti:=true
here what it looks like;
We have a set of users who have an outlook template (with same name) stored in their machines.
I want to create a hyperlink clicking on which will open that .oft file from their machine and they can use it further. Basically I need to know whether by using any script, we can get the location/machine name or not.
Is that possible?
Environment variables provide this type of information.
http://www.slipstick.com/developer/windows-environment-variables-outlook-macros/
Sub EnumSEVars()
Dim strVar As String
Dim i As Long
For i = 1 To 255
strVar = Environ$(i)
If LenB(strVar) = 0& Then Exit For
Debug.Print strVar
Next
End Sub
http://www.askvg.com/list-of-environment-variables-in-windows-xp-vista-and-7/
http://ss64.com/nt/syntax-variables.html
This function, when clicked on should ideally copy all of worksheet 2 to another workbook and save that sheet as a csv file. its not working... and i don't know how to tell it where to save the file (i want it to save to desktop). help please?
Is there any easier way i can do this?
Private Sub CommandButton2_Click()
'save as csv'
fname = "cambs_uploader.csv"
Sheet2.SaveAs fname, xlCSV
End Sub
If it's as simple as saving to your desktop every time then you can just put the full path in the string, rather than just the file name. However, if you want to save it by selection from a directory tree, then the easiest way in Excel is to use its Application.GetSaveAsFilename() method.
Documentation: http://msdn.microsoft.com/en-us/library/office/ff195734.aspx
Example:
Sub CommandButton2_Click()
Dim fName As String
Dim saveSheet As Worksheet
Set saveSheet = ActiveWorkbook.Sheets("Sheet2") ' Change your sheet name
saveSheet.SaveAs Application.GetSaveAsFilename("cambs_uploader.csv", ".csv", 1, "Save File")
Set saveSheet = Nothing
Exit Sub