Getting An Absolute Image Path - ms-access-2007

I want to get an absolute path to images folder with the image name (e.g \image1.jpg) at the end of the path, where ImagePath is the name of the image path field in the table. I am just not sure how to correctly format it.
How would I do this?
Here is what I have tried already:
=IIf(IsNull([ImagePath]),Null,GetPath() & "C:\Criminal Records Database\Persons_Images\" & [ImagePath])

GetUNCPath is a method to translate any path into the a Universal Naming Convention path, across network drives. It will return a local drive as an absolute path if not networked. I use this function to guarantee I have a full absolute path.
I wrote the code below (with some assistance from #GSerg) to make it easy to convert a path into a full absolute UNC path.
Usage
Dim fullPath as string
fullPath = GetUNCPath("T:\SomeDir\SomeFile.Txt")
It will convert T:\SomeDir\SomeFile.Txt into \\SomeServer\SomeShare\SomeDir\SomeFile.Txt
This has been tested on Access 2003 and Access 2010. It is 32-bit and 64-bit compatible.
Module: GetUNC
Option Compare Database
Option Explicit
#If VBA7 Then
Private Declare PtrSafe Function WNetGetConnection Lib "mpr.dll" Alias "WNetGetConnectionW" (ByVal lpLocalName As LongPtr, ByVal lpRemoteName As Long, lpnLength As Long) As Long
Private Declare PtrSafe Function PathIsUNC Lib "shlwapi.dll" Alias "PathIsUNCW" (ByVal pszPath As LongPtr) As Long
Private Declare PtrSafe Function PathIsNetworkPath Lib "shlwapi.dll" Alias "PathIsNetworkPathW" (ByVal pszPath As LongPtr) As Long
Private Declare PtrSafe Function PathStripToRoot Lib "shlwapi.dll" Alias "PathStripToRootW" (ByVal pPath As LongPtr) As LongPtr
Private Declare PtrSafe Function PathSkipRoot Lib "shlwapi.dll" Alias "PathSkipRootW" (ByVal pPath As LongPtr) As Long
Private Declare PtrSafe Function PathRemoveBackslash Lib "shlwapi.dll" Alias "PathRemoveBackslashW" (ByVal strPath As LongPtr) As LongPtr
#Else
Private Declare Function WNetGetConnection Lib "mpr.dll" Alias "WNetGetConnectionW" (ByVal lpLocalName As Long, ByVal lpRemoteName As Long, lpnLength As Long) As Long
Private Declare Function PathIsUNC Lib "shlwapi.dll" Alias "PathIsUNCW" (ByVal pszPath As Long) As Long
Private Declare Function PathIsNetworkPath Lib "shlwapi.dll" Alias "PathIsNetworkPathW" (ByVal pszPath As Long) As Long
Private Declare Function PathStripToRoot Lib "shlwapi.dll" Alias "PathStripToRootW" (ByVal pPath As Long) As Long
Private Declare Function PathSkipRoot Lib "shlwapi.dll" Alias "PathSkipRootW" (ByVal pPath As Long) As Long
Private Declare Function PathRemoveBackslash Lib "shlwapi.dll" Alias "PathRemoveBackslashW" (ByVal strPath As Long) As Long
#End If
Public Function GetUNCPath(sLocalPath As String) As String
Dim lResult As Long
#If VBA7 Then
Dim lpResult As LongPtr
#Else
Dim lpResult As Long
#End If
Dim ASLocal As APIString
Dim ASPath As APIString
Dim ASRoot As APIString
Dim ASRemoteRoot As APIString
Dim ASTemp As APIString
Set ASLocal = New APIString
ASLocal.Value = sLocalPath
If ASLocal.Pointer > 0 Then
lResult = PathIsUNC(ASLocal.Pointer)
End If
If lResult <> 0 Then
GetUNCPath = ASLocal.Value
Exit Function
End If
If ASLocal.Pointer > 0 Then
lResult = PathIsNetworkPath(ASLocal.Pointer)
End If
If lResult = 0 Then
GetUNCPath = ASLocal.Value
Exit Function
End If
' Extract Root
Set ASRoot = New APIString
ASRoot.Value = sLocalPath
If ASRoot.Length = 2 And Mid(ASRoot.Value, 2, 1) = ":" Then
' We have a Root with no Path
Set ASPath = New APIString
ASPath.Value = ""
Else
If ASRoot.Pointer > 0 Then
lpResult = PathStripToRoot(ASRoot.Pointer)
End If
ASRoot.TruncToNull
If ASRoot.Pointer > 0 And Mid(ASRoot.Value, ASRoot.Length) = "\" Then
lpResult = PathRemoveBackslash(ASRoot.Pointer)
ASRoot.TruncToPointer lpResult
End If
' Extract Path
Set ASPath = New APIString
ASPath.Value = sLocalPath
lpResult = PathSkipRoot(ASPath.Pointer)
ASPath.TruncFromPointer lpResult
If ASPath.Length > 0 Then
If ASPath.Pointer > 0 And Mid(ASPath.Value, ASPath.Length) = "\" Then
lpResult = PathRemoveBackslash(ASPath.Pointer)
ASPath.TruncToPointer lpResult
End If
End If
End If
' Resolve Local Root into Remote Root
Set ASRemoteRoot = New APIString
ASRemoteRoot.Init 255
If ASRoot.Pointer > 0 And ASRemoteRoot.Pointer > 0 Then
lResult = WNetGetConnection(ASRoot.Pointer, ASRemoteRoot.Pointer, LenB(ASRemoteRoot.Value))
End If
ASRemoteRoot.TruncToNull
GetUNCPath = ASRemoteRoot.Value & ASPath.Value
End Function
Class Module: APIString
Option Compare Database
Option Explicit
Private sBuffer As String
Private Sub Class_Initialize()
sBuffer = vbNullChar
End Sub
Private Sub Class_Terminate()
sBuffer = ""
End Sub
Public Property Get Value() As String
Value = sBuffer
End Property
Public Property Let Value(ByVal sNewStr As String)
sBuffer = sNewStr
End Property
' Truncates Length
#If VBA7 Then
Public Sub TruncToPointer(ByVal lpNewUBound As LongPtr)
#Else
Public Sub TruncToPointer(ByVal lpNewUBound As Long)
#End If
Dim lpDiff As Long
If lpNewUBound <= StrPtr(sBuffer) Then Exit Sub
lpDiff = (lpNewUBound - StrPtr(sBuffer)) \ 2
sBuffer = Mid(sBuffer, 1, lpDiff)
End Sub
' Shifts Starting Point forward
#If VBA7 Then
Public Sub TruncFromPointer(ByVal lpNewLBound As LongPtr)
#Else
Public Sub TruncFromPointer(ByVal lpNewLBound As Long)
#End If
Dim lDiff As Long
If lpNewLBound <= StrPtr(sBuffer) Then Exit Sub
If lpNewLBound >= (StrPtr(sBuffer) + LenB(sBuffer)) Then
sBuffer = ""
Exit Sub
End If
lDiff = (lpNewLBound - StrPtr(sBuffer)) \ 2
sBuffer = Mid(sBuffer, lDiff)
End Sub
Public Sub Init(Size As Long)
sBuffer = String(Size, vbNullChar)
End Sub
Public Sub TruncToNull()
Dim lPos As Long
lPos = InStr(sBuffer, vbNullChar)
If lPos = 0 Then Exit Sub
sBuffer = Mid(sBuffer, 1, lPos - 1)
End Sub
Public Property Get Length() As Long
Length = Len(sBuffer)
End Property
#If VBA7 Then
Public Property Get Pointer() As LongPtr
#Else
Public Property Get Pointer() As Long
#End If
Pointer = StrPtr(sBuffer)
End Property

Related

Ms access VBA copy form data

I'm currently making a ms access database and I have made a form where the user inputs data. I would like the user to be able to press a button which copies the label and the entered data so they can paste it elsewhere. I have found a project which achieves exactly what I want however I cannot seem to get it to work for my application. The code below is what I found online and this is the link to the thread. It is the one labeled copypaste.zip https://www.access-programmers.co.uk/forums/threads/copy-all-date-on-form-to-clipboard-to-user-can-past-this-into-another-system.309872/ .Thank you.
This is on the module code:
Option Compare Database
Option Explicit
Private Declare Function OpenClipboard Lib "user32.dll" (ByVal hWnd As Long) As Long
Private Declare Function EmptyClipboard Lib "user32.dll" () As Long
Private Declare Function CloseClipboard Lib "user32.dll" () As Long
Private Declare Function IsClipboardFormatAvailable Lib "user32.dll" (ByVal wFormat As Long) As Long
Private Declare Function GetClipboardData Lib "user32.dll" (ByVal wFormat As Long) As Long
Private Declare Function SetClipboardData Lib "user32.dll" (ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare Function GlobalAlloc Lib "kernel32.dll" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function lstrcpy Lib "kernel32.dll" Alias "lstrcpyW" (ByVal lpString1
As Long, ByVal lpString2 As Long) As Long
Public Sub SetClipboard(sUniText As String)
Dim iStrPtr As Long
Dim iLen As Long
Dim iLock As Long
Const GMEM_MOVEABLE As Long = &H2
Const GMEM_ZEROINIT As Long = &H40
Const CF_UNICODETEXT As Long = &HD
OpenClipboard 0&
EmptyClipboard
iLen = LenB(sUniText) + 2&
iStrPtr = GlobalAlloc(GMEM_MOVEABLE Or GMEM_ZEROINIT, iLen)
iLock = GlobalLock(iStrPtr)
lstrcpy iLock, StrPtr(sUniText)
GlobalUnlock iStrPtr
SetClipboardData CF_UNICODETEXT, iStrPtr
CloseClipboard
End Sub
Public Function GetClipboard() As String
Dim iStrPtr As Long
Dim iLen As Long
Dim iLock As Long
Dim sUniText As String
Const CF_UNICODETEXT As Long = 13&
OpenClipboard 0&
If IsClipboardFormatAvailable(CF_UNICODETEXT) Then
iStrPtr = GetClipboardData(CF_UNICODETEXT)
If iStrPtr Then
iLock = GlobalLock(iStrPtr)
iLen = GlobalSize(iStrPtr)
sUniText = String$(iLen \ 2& - 1&, vbNullChar)
lstrcpy StrPtr(sUniText), iLock
GlobalUnlock iStrPtr
End If
GetClipboard = sUniText
End If
CloseClipboard
End Function
This is on the form code:
Option Compare Database
Option Explicit
Private Sub Command6_Click()
Dim strSql As String
Dim ctl As Variant
For Each ctl In Me.Controls
If ctl.Tag = "?" Then
strSql = strSql & ctl.Controls(0).Caption & " " & Nz(ctl, "") & vbNewLine
End If
Next
Me.Text4 = ""
Me.Text4 = strSql
Me.Text7 = ""
SetClipboard strSql
End Sub
That is much code for nothing. This will do:
Private Sub CommandCopy_Click()
Dim Control As Control
Dim Value As String
For Each Control In Me.Controls
If Control.Tag = "?" Then
Value = Value & Control.Caption & " " & Nz(Control.Value) & vbNewLine
End If
Next
' Renamed Text4.
Me!ValueCopy.Value = Value
Me!ValueCopy.SetFocus
DoCmd.RunCommand acCmdCopy
End Sub

StringFromIID in VBA - what's a nice way to avoid managing the memory manually?

I would like to call this function in VBA:
HRESULT StringFromIID(
REFIID rclsid,
LPOLESTR *lplpsz
);
... to print a REFIID for debugging. I've translated to VBA:
Private Declare PtrSafe Function StringFromIID Lib "ole32" (ByVal rclsid As LongPtr, ByVal lpsz As LongPtr) As Long
however I'm not sure what to pass for the second parameter, and am also worried about how to release the memory.
Given a pointer to an interface ID, how can I get a string in a VBA idiomatic way?
Here is a quick implementation of a few useful functions. Note I am using StringFromCLSID instead of StringFromIID but you get the idea:
Option Explicit
Public Declare PtrSafe Function CLSIDFromString Lib "ole32.dll" (ByVal lpsz As LongPtr, ByRef pclsid As Any) As Long
Public Declare PtrSafe Function StringFromCLSID Lib "ole32.dll" (ByRef rclsid As Any, ByRef lplpsz As LongPtr) As Long
Public Declare PtrSafe Function ProgIDFromCLSID Lib "ole32.dll" (ByRef clsID As Any, ByRef lplpszProgID As LongPtr) As Long
Public Declare PtrSafe Function SysReAllocString Lib "oleaut32.dll" (ByVal pBSTR As LongPtr, Optional ByVal pszStrPtr As LongPtr) As Long
Public Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (Optional ByVal pv As LongPtr)
Public Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(0 To 7) As Byte
End Type
Public Function GetProgIDFromCLSIDString(ByVal clsidString As String) As String
Const S_OK As Long = 0
Dim gID As GUID
Dim resPtr As LongPtr
'
If CLSIDFromString(StrPtr(clsidString), gID) = S_OK Then
If ProgIDFromCLSID(gID, resPtr) = S_OK Then
SysReAllocString VarPtr(GetProgIDFromCLSIDString), resPtr
CoTaskMemFree resPtr
End If
End If
End Function
Public Function GetStringFromCLSID(ByRef clsID As GUID) As String
Const S_OK As Long = 0
Dim resPtr As LongPtr
'
If StringFromCLSID(clsID, resPtr) = S_OK Then
SysReAllocString VarPtr(GetStringFromCLSID), resPtr
CoTaskMemFree resPtr
End If
End Function
Public Function GetCLSIDFromString(ByVal clsID As String) As GUID
Const S_OK As Long = 0
Dim gID As GUID
'
If CLSIDFromString(StrPtr(clsID), gID) = S_OK Then
GetCLSIDFromString = gID
End If
End Function
A quick test:
Sub Test()
Const clsID As String = "{00020400-0000-0000-C000-000000000046}"
Dim gID As GUID: gID = GetCLSIDFromString(clsID)
Debug.Print GetStringFromCLSID(gID) 'Returns original clsID
End Sub
If you want something that works on a MAC then use this version which is a bit more polished than the one above:
Option Explicit
Option Private Module
Option Compare Binary
#If Mac Then
#ElseIf VBA7 Then
Private Declare PtrSafe Function CLSIDFromString Lib "ole32.dll" (ByVal lpsz As LongPtr, ByRef pclsid As Any) As Long
Private Declare PtrSafe Function ProgIDFromCLSID Lib "ole32.dll" (ByRef clsID As Any, ByRef lplpszProgID As LongPtr) As Long
Private Declare PtrSafe Function StringFromCLSID Lib "ole32.dll" (ByRef rclsid As Any, ByRef lplpsz As LongPtr) As Long
Private Declare PtrSafe Function SysReAllocString Lib "oleaut32.dll" (ByVal pBSTR As LongPtr, Optional ByVal pszStrPtr As LongPtr) As Long
Private Declare PtrSafe Sub CoTaskMemFree Lib "ole32.dll" (Optional ByVal pv As LongPtr)
#Else
Private Declare Function CLSIDFromString Lib "ole32.dll" (ByVal lpsz As Long, ByRef pclsid As Any) As Long
Private Declare Function ProgIDFromCLSID Lib "ole32.dll" (ByRef clsID As Any, ByRef lplpszProgID As Long) As Long
Private Declare Function StringFromCLSID Lib "ole32.dll" (ByRef rclsid As Any, ByRef lplpsz As Long) As Long
Private Declare Function SysReAllocString Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long) As Long
Private Declare Sub CoTaskMemFree Lib "ole32.dll" (Optional ByVal pv As Long)
#End If
Public Type GUID
data1 As Long
data2 As Integer
data3 As Integer
data4(0 To 7) As Byte
End Type
Public Const S_OK As Long = 0
'OLE Automation Protocol GUIDs
Public Const IID_IRecordInfo = "{0000002F-0000-0000-C000-000000000046}"
Public Const IID_IDispatch = "{00020400-0000-0000-C000-000000000046}"
Public Const IID_ITypeComp = "{00020403-0000-0000-C000-000000000046}"
Public Const IID_ITypeInfo = "{00020401-0000-0000-C000-000000000046}"
Public Const IID_ITypeInfo2 = "{00020412-0000-0000-C000-000000000046}"
Public Const IID_ITypeLib = "{00020402-0000-0000-C000-000000000046}"
Public Const IID_ITypeLib2 = "{00020411-0000-0000-C000-000000000046}"
Public Const IID_IUnknown = "{00000000-0000-0000-C000-000000000046}"
Public Const IID_IEnumVARIANT = "{00020404-0000-0000-C000-000000000046}"
Public Const IID_NULL = "{00000000-0000-0000-0000-000000000000}"
'*******************************************************************************
'Converts a string to a GUID struct
'Note that 'CLSIDFromString' win API is only slightly faster (<10%) compared
' to the pure VB approach (used for MAc only) but it has the advantage of
' raising other types of errors (like class is not in registry)
'*******************************************************************************
#If Mac Then
Public Function GUIDFromString(ByVal sGUID As String) As GUID
Const methodName As String = "GUIDFromString"
Const hexPrefix As String = "&H"
Static pattern As String
'
If pattern = vbNullString Then pattern = Replace(IID_NULL, "0", "[0-9A-F]")
If Not sGUID Like pattern Then Err.Raise 5, methodName, "Invalid string"
'
Dim parts() As String: parts = Split(Mid$(sGUID, 2, Len(sGUID) - 2), "-")
Dim I As Long
'
With GUIDFromString
.data1 = CLng(hexPrefix & parts(0))
.data2 = CInt(hexPrefix & parts(1))
.data3 = CInt(hexPrefix & parts(2))
For I = 0 To 1
.data4(I) = CByte(hexPrefix & Mid$(parts(3), I * 2 + 1, 2))
Next I
For I = 2 To 7
.data4(I) = CByte(hexPrefix & Mid$(parts(4), (I - 1) * 2 - 1, 2))
Next I
End With
End Function
#Else
'https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-clsidfromstring
Public Function GUIDFromString(ByVal sGUID As String) As GUID
Const methodName As String = "GUIDFromString"
Dim hResult As Long: hResult = CLSIDFromString(StrPtr(sGUID), GUIDFromString)
If hResult <> S_OK Then Err.Raise hResult, methodName, "Invalid string"
End Function
#End If
'*******************************************************************************
'Converts a GUID struct to a string
'Note that this approach is 4 times faster than running a combination of the
' following 3 Windows APIs: StringFromCLSID, SysReAllocString, CoTaskMemFree
'*******************************************************************************
Public Function GUIDToString(ByRef gID As GUID) As String
Dim parts(0 To 4) As String
'
With gID
parts(0) = AlignHex(Hex$(.data1), 8)
parts(1) = AlignHex(Hex$(.data2), 4)
parts(2) = AlignHex(Hex$(.data3), 4)
parts(3) = AlignHex(Hex$(.data4(0) * 256& + .data4(1)), 4)
parts(4) = AlignHex(Hex$(.data4(2) * 65536 + .data4(3) * 256& + .data4(4)) _
& Hex$(.data4(5) * 65536 + .data4(6) * 256& + .data4(7)), 12)
End With
GUIDToString = "{" & Join(parts, "-") & "}"
End Function
Private Function AlignHex(ByRef h As String, ByVal charsCount As Long) As String
Const maxHex As String = "0000000000000000" '16 chars (LongLong max chars)
If Len(h) < charsCount Then
AlignHex = Right$(maxHex & h, charsCount)
Else
AlignHex = h
End If
End Function
'*******************************************************************************
'Converts a CLSID string to a progid string. Windows only
'Returns an empty string if not successful
'*******************************************************************************
#If Mac Then
#Else
Public Function GetProgIDFromCLSID(ByRef cID As GUID) As String
#If VBA7 Then
Dim resPtr As LongPtr
#Else
Dim resPtr As Long
#End If
If ProgIDFromCLSID(cID, resPtr) = S_OK Then
SysReAllocString VarPtr(GetProgIDFromCLSID), resPtr
CoTaskMemFree resPtr
End If
End Function
#End If

How do I fix error for 64-bit VBA PPT converted from 32-bit

This VBA program worked for 32-bit PPT 2007 but when I used it for 64-bit PPT 2013, there was an error even when I added PtrSafe infront of Public Declare.
There was a type miss match in this function: AddressOf BrowseCallbackProc
(in the middle of Public Function Get_IMGFolderName())
I would like some advice on how to solve this problem.
I have been coding as a hobby so I do not know much.
Thankyou
Option Explicit
Public Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long
Public Declare PtrSafe Function SHBrowseForFolder Lib "shell32" (lpbi As BrowseInfo) As Long
Public Declare PtrSafe Function SHGetPathFromIDList Lib "shell32" (ByVal pidList As Long, ByVal lpBuffer As String) As Long
Public Declare PtrSafe Function lstrcat Lib "kernel32" Alias "lstrcatA" (ByVal lpString1 As String, ByVal lpString2 As String) As Long
Public Type BrowseInfo
hwndOwner As Long
pIDLRoot As Long
pszDisplayName As Long
lpszstrMsg As Long
ulFlags As Long
lpfnCallback As Long
lParam As Long
iImage As Long
End Type
Public Const BIF_STATUSTEXT = &H4&
Public Const BIF_RETURNONLYFSDIRS = 1
Public Const BIF_DONTGOBELOWDOMAIN = 2
Public Const MAX_PATH = 260
Public Const WM_USER = &H400
Public Const BFFM_INITIALIZED = 1
Public Const BFFM_SELCHANGED = 2
Public Const BFFM_SETSTATUSTEXT = (WM_USER + 100)
Public Const BFFM_SETSELECTION = (WM_USER + 102)
Public strCurDir As String '현재 디렉토리
Public Enum CHOOSE_COLOR_FLAGS
CC_RGBINIT = &H1&
CC_FULLOPEN = &H2&
CC_PREVENTFULLOPEN = &H4&
CC_SHOWHELP = &H8&
CC_ENABLEHOOK = &H10&
CC_ENABLETEMPLATE = &H20&
CC_ENABLETEMPLATEHANDLE = &H40&
CC_SOLIDCOLOR = &H80&
CC_ANYCOLOR = &H100&
End Enum
Private Type CHOOSECOLOR
lStructSize As Long
hwndOwner As Long
hInstance As Long
rgbResult As Long
lpCustColors As Long
flags As CHOOSE_COLOR_FLAGS
lCustData As Long
lpfnHook As Long
lpTemplateName As String
End Type
Private Declare PtrSafe Function ChooseColor_API Lib "comdlg32.dll" Alias "ChooseColorA" (lpChoosecolor As CHOOSECOLOR) As Long
Function Delete_Sheets()
'ActiveWindow.View.GotoSlide ActivePresentation.Slides.Count
While ActivePresentation.Slides.Count > 0
ActiveWindow.Selection.SlideRange.Delete
Wend
End Function
Public Function Get_IMGFolderName() As String
Dim lpIDList As Long
Dim szstrMsg As String
Dim strBuffer As String
Dim tBrowseInfo As BrowseInfo
Dim strDir As String
strCurDir = frmBible.lblIMGFolder.Caption & vbNullChar
szstrMsg = "바탕그림용 이미지가 들어 있는 폴더를 지정해주세요"
With tBrowseInfo
.hwndOwner = 0
.lpszstrMsg = lstrcat(szstrMsg, "")
.ulFlags = BIF_RETURNONLYFSDIRS + BIF_DONTGOBELOWDOMAIN + BIF_STATUSTEXT
.lpfnCallback = GetAddressofFunction(AddressOf BrowseCallbackProc) 'get address of function.
End With
lpIDList = SHBrowseForFolder(tBrowseInfo)
If (lpIDList) Then
strBuffer = Space(MAX_PATH)
SHGetPathFromIDList lpIDList, strBuffer
strBuffer = Left(strBuffer, InStr(strBuffer, vbNullChar) - 1)
Get_IMGFolderName = strBuffer
Else
Get_IMGFolderName = ""
End If
End Function
Public Function Remove_Special_Chars(intxt) As String
Dim wkstr As String
Dim p As Integer, c, uc
wkstr = ""
While Len(intxt) > 0
c = Left(intxt, 1)
uc = UCase(c)
If c >= "가" And c <= "힝" Then
wkstr = wkstr & c
ElseIf uc >= "A" And uc <= "Z" Then
wkstr = wkstr & c
ElseIf uc >= "0" And uc <= "9" Then
wkstr = wkstr & c
End If
intxt = Mid(intxt, 2)
Wend
Remove_Special_Chars = wkstr
End Function
Public Function Return_PathName(full_Path As String)
'return path name only
Dim p As Integer, ps As Integer
ps = 1
p = 1
Do While p > 0
p = InStr(ps, full_Path, "\", vbBinaryCompare)
If p > 0 Then
ps = p + 1
End If
Loop
Return_PathName = Left(full_Path, ps - 1)
End Function
Public Function Return_FileName(full_Path As String)
' return file name only
Dim p As Integer, ps As Integer
ps = 1
p = 1
Do While p > 0
p = InStr(ps, full_Path, "\", vbBinaryCompare)
If p > 0 Then
ps = p + 1
End If
Loop
Return_FileName = Mid(full_Path, ps)
End Function
Public Function Return_FolderName(full_Path)
' return folder name only
Dim p As Integer
p = InStrRev(full_Path, "\", Len(full_Path) - 1)
Return_FolderName = Mid(full_Path, p + 1)
End Function
Public Function BrowseCallbackProc(ByVal hWnd As Long, ByVal uMsg As Long, ByVal lp As Long, ByVal pData As Long) As Long
Dim lpIDList As Long
Dim lngRet As Long
Dim strBuffer As String
On Error Resume Next
Select Case uMsg
Case BFFM_INITIALIZED
Call SendMessage(hWnd, BFFM_SETSELECTION, 1, strCurDir)
Case BFFM_SELCHANGED
strBuffer = Space(MAX_PATH)
lngRet = SHGetPathFromIDList(lp, strBuffer)
If lngRet = 1 Then
Call SendMessage(hWnd, BFFM_SETSTATUSTEXT, 0, strBuffer)
End If
End Select
On Error GoTo 0
BrowseCallbackProc = 0
End Function
Public Function GetAddressofFunction(lngAdd As Long) As Long
GetAddressofFunction = lngAdd
End Function
Public Function FileDateInfo(filespec)
Dim fs, f
Set fs = CreateObject("Scripting.FileSystemObject")
Set f = fs.GetFile(filespec)
FileDateInfo = f.DateLastModified
End Function
Public Function WinRegistry_CommonGet()
Dim TmpName As String
Dim i As Integer
Dim x
Version_Release = GetSetting("BibleChoir", "LatestVal", "Version_Release", "vv.rr")
frmBible.lblIMGFolder.Caption = GetSetting("BibleChoir", "LatestVal", "IMGFolder", "없음")
'frmPicture.sldBright = GetSetting(appname:="BibleChoir", section:="LatestVal", key:="Bright", Default:=70)
frmBible.chkEachPage = GetSetting("BibleChoir", "LatestVal", "EachPage", False)
File2Open = frmBible.lblIMGFolder.Caption
If File2Open <> "없음" Then
On Error Resume Next
frmBible.ImgPreview.Picture = LoadPicture(File2Open)
End If
On Error GoTo 0
End Function
Public Function WinRegistry_CommonSave()
Dim i As Integer
SaveSetting "BibleChoir", "LatestVal", "Version_Release", Version_Release
SaveSetting "BibleChoir", "LatestVal", "IMGFolder", frmBible.lblIMGFolder.Caption
'SaveSetting "BibleChoir", "LatestVal", "Bright", frmPicture.sldBright
SaveSetting "BibleChoir", "LatestVal", "EachPage", frmBible.chkEachPage
End Function
You need to do more than just add the PtrSafe declaration. Some of your Long data types also need to be converted to LongPtr.
#If VBA7 Then
Public Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, _
ByVal lParam As String) As LongPtr
Public Declare PtrSafe Function SHBrowseForFolder Lib "shell32" _
(lpbi As BrowseInfo) As LongPtr
Public Declare PtrSafe Function SHGetPathFromIDList Lib "shell32" _
(ByVal pidList As LongPtr, ByVal lpBuffer As String) As LongPtr
Public Declare PtrSafe Function lstrcat Lib "kernel32" Alias "lstrcatA" _
(ByVal lpString1 As String, ByVal lpString2 As String) As Long
#Else
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
ByVal lParam As String) As Long
Public Declare Function SHBrowseForFolder Lib "shell32" _
(lpbi As BrowseInfo) As Long
Public Declare Function SHGetPathFromIDList Lib "shell32" _
(ByVal pidList As Long, ByVal lpBuffer As String) As Long
Public Declare Function lstrcat Lib "kernel32" Alias "lstrcatA" _
(ByVal lpString1 As String, ByVal lpString2 As String) As Long
#End If
From Microsoft Docs:
Note Declare statements with the PtrSafe keyword is the recommended syntax. Declare statements that include PtrSafe work correctly in the VBA7 development environment on both 32-bit and 64-bit platforms only after all data types in the Declare statement (parameters and return values) that need to store 64-bit quantities are updated to use LongLong for 64-bit integrals or LongPtr for pointers and handles. To ensure backwards compatibility with VBA version 6 and earlier use the following construct:
#If VBA7 Then
Declare PtrSafe Sub...
#Else
Declare Sub...
#EndIf
When running in 64-bit versions of Office Declare statements must include the PtrSafe keyword. The PtrSafe keyword asserts that a Declare statement is safe to run in 64-bit development environments. Adding the PtrSafe keyword to a Declare statement only signifies the Declare statement explicitly targets 64-bits, all data types within the statement that need to store 64-bits (including return values and parameters) must still be modified to hold 64-bit quantities using either LongLong for 64-bit integrals or LongPtr for pointers and handles.

Save embedded PDFs in Word file

I need a VBA macro for MS Word 2013 to save the embedded PDF attachments in the Word file into a folder.
I found a working solution in Excel which saves embedded files in the Excel document, I have made some modifications to work in Word VBA, but it doesn't work any ideas to make it work in Word ?
Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
Private Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare PtrSafe Function GlobalSize Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hWnd As Long) As Long
Private Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare PtrSafe Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long
Private Declare PtrSafe Sub RtlMoveMemory Lib "kernel32" (Destination As Any, Source As Any, ByVal Length As Long)
Sub Embed_Files_Save_PDF_Run()
For Each file In ThisDocument.InlineShapes
Call Embed_Files_Save_PDF(file)
Next
End Sub
Sub Embed_Files_Save_PDF(ByVal Embedded_PDF)
On Error Resume Next
Dim PDF_Path As String
PDF_Path = ActiveDocument.Path
If Right$(PDF_Path, 1) <> Application.PathSeparator Then PDF_Path = PDF_Path & Application.PathSeparator
Dim PDF_Name As String
PDF_Name = UCase$(Left$(Embedded_PDF.OLEFormat.IconLabel, 1)) & Mid$(Embedded_PDF.OLEFormat.IconLabel, 2)
PDF_Name = PDF_Name & ".PDF"
Dim FileEOF As Long
Dim FileLOF As Long
Dim CB_Lock As Long ' ClipBoard Lock
Dim CB_Size As Long ' ClibBoard Size
Dim PDF_File() As Byte
Dim Temp_PDF() As Byte
Embedded_PDF.Copy
If OpenClipboard(0) Then
Counter = GetClipboardData(49156)
If Counter <> 0 Then CB_Size = GlobalSize(Counter)
If CB_Size <> 0 Then CB_Lock = GlobalLock(Counter)
If CB_Lock <> 0 Then
ReDim Temp_PDF(1 To CLng(CB_Size))
RtlMoveMemory Temp_PDF(1), ByVal CB_Lock, CB_Size
Call GlobalUnlock(Counter)
Counter = InStrB(Temp_PDF, StrConv("%PDF", vbFromUnicode))
If Counter > 0 Then
FileEOF = InStrB(Counter, Temp_PDF, StrConv("%%EOF", vbFromUnicode))
While FileEOF
FileLOF = FileEOF - Counter + 7
FileEOF = InStrB(FileEOF + 5, Temp_PDF, StrConv("%%EOF", vbFromUnicode))
Wend
ReDim PDF_File(1 To FileLOF)
For FileEOF = 1 To FileLOF
PDF_File(FileEOF) = Temp_PDF(Counter + FileEOF - 1)
Next
End If
End If
CloseClipboard
If Counter > 0 Then
Counter = FreeFile
Open PDF_Path & PDF_Name For Binary As #Counter
Put #Counter, 1, PDF_File
Close #Counter
End If
End If
Set Embedded_PDF = Nothing
End Sub
Any help would be appreciated.
try this
it does not save the pdf file but it opens it in acrobat so that you can save it
Sub pdfExtract()
' opens embedded pdf file in acrobat reader for saving
Dim shap As InlineShape
For Each shap In ActiveDocument.InlineShapes
If Not shap.OLEFormat Is Nothing Then
If shap.OLEFormat.ClassType = "AcroExch.Document.DC" Then
shap.OLEFormat.DoVerb wdOLEVerbOpen
End If
End If
Next shap
End Sub

How to make VBA code compatible with 64-bit Excel?

I have an excel running with VB code and it seems fine with 32 version and now when I tested in office 2016 it gives the below error
The code in this project must be updated for use on 64-bit systems
Since I am not good in vb I have issues with updating the code. This is my code below and how to update it for the 64-bit compatibility,
Declare Function GetSystemDirectory Lib "kernel64" Alias "GetSystemDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
'a íÌÈ Ãí íßæä åäÇß ÌÏæá Úáì ÞÇÚÏÉ ÇáãÚáæãÇÊ ÈÅÓã
'a QtrDate
Global G_SystemPath As String
Function L_FileExist(L_FName As String) As Boolean
'a chick if the file given is found or not
'a input File Name
'a Output
'a True : if found
'a False : if not found
L_FileExist = Not (Trim(Dir(L_FName)) = "")
End Function
Public Function GetWindowsSysDir() As String
Dim strBuf As String
strBuf = Space$(250)
If GetSystemDirectory(strBuf, 250) Then
GetWindowsSysDir = StringFromBuffer(strBuf)
AddDirSep GetWindowsSysDir
End If
End Function
Public Function StringFromBuffer(Buffer As String) As String
Dim nPos As Long
nPos = InStr(Buffer, vbNullChar)
If nPos > 0 Then
StringFromBuffer = Left$(Buffer, nPos - 1)
Else
StringFromBuffer = Buffer
End If
End Function
Public Sub AddDirSep(strPathName As String)
strPathName = RTrim$(strPathName)
If Right$(strPathName, 1) <> "\" Then
strPathName = strPathName & "\"
End If
End Sub
Sub L_Secrit()
G_SystemPath = GetWindowsSysDir
If L_FileExist(G_SystemPath & "MSAYAR.DLL") Then
Sheet1.Cells(400, 2) = " "
Sheet1.Cells(401, 2) = " "
Sheet1.Cells(402, 2) = " "
The first line should be
#if VBA7 then
Declare PtrSafe Function GetSystemDirectory Lib "kernel32" Alias "GetSystemDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
#else
Declare Function GetSystemDirectory Lib "kernel32" Alias "GetSystemDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long
#end if
Here is a nice resource to find 64bit Win32API calls.