I have a xls/csv list of images:
Name image url
test.jpg http://test.com/232dd.jpg
test2.jpg http://test.com/2390j.jpg
I have about 200 of these...is there a way to download the list and name them as identified in the xls file?
Here is my Excel VBA:
Private Declare Function URLDownloadToFile Lib "urlmon" _
Alias "URLDownloadToFileA" (ByVal pCaller As Long, _
ByVal szURL As String, ByVal szFileName As String, _
ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
Private Sub download_pics()
Dim rng As Range
Dim cell As Variant
Set rng = Range("A1:B10")
For Each cell In rng
' Download the file.
URLDownloadToFile 0, cell(rng, 2).Value, "C:\" & cell(rng, 1).Value, 0, 0
Next
End Sub
Running into type mismatch error with URLDownloadToFile
OK The type mismatch has to do with your iteration. You need to specify how you're iterating over rng with the For each cell in rng statement, like:
For each cell in rng.Rows
Otherwise, it treats that statement as For each cell in rng.Cells and that raises the mismatch error.
I made some modifications to the code (based on Sid's answer here), so it checks to ensure the file downloaded successfully, but mostly what you found was correct, you just need to implement it a little differently.
Private Declare Function URLDownloadToFile Lib "urlmon" _
Alias "URLDownloadToFileA" (ByVal pCaller As Long, _
ByVal szURL As String, ByVal szFileName As String, _
ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
Private Sub download_pics()
Dim rng As Range
Dim myRow As Range
Dim imgName As String
Dim fileLocation As String
Dim Ret As Long 'return value from the URLDownloadToFile function
Set rng = Range("A1:B10")
For Each myRow In rng.Rows
With myRow
imgName = .Columns(2).Value
fileLocation = "C:\" & .Columns(1).Value
With .Columns(1).Offset(, 2)
If URLDownloadToFile(0, imgName, fileLocation, 0, 0) = 0 Then
.Value = "downloaded successfully"
Else:
.Value = "download failed!"
End If
End With
End With
Next
End Sub
Related
I have to edit an old legacy VB6 application so that it can edit the registry to write the following:
reg add "HKCU\Software\Microsoft\Print\UnifiedPrintDialog" /v "PreferLegacyPrintDialog" /d 1 /t REG_DWORD /f
How can I emulate the above command in VB6?
I read a few posts using the registry = CreateObject("WScript.shell") methodology but it doesn't seem clear to me and I really don't want to mess around with the registry without knowing what I'm doing. Otherwise, could I just run the command through a ShellExecute or something similar?
Any assistance would be appreciated. Thanks!
For "proper" registry access/read/write in VB6, you would need to implement the appropriate Win32 API methods. Here's a wrapper class for that. But for your simple need, the WScript.Shell approach should it (from the Windows Scripting Host helpfile):
RegWrite supports strType as REG_SZ, REG_EXPAND_SZ, REG_DWORD, and
REG_BINARY. If another data type is passed as strType, RegWrite
returns E_INVALIDARG.
RegWrite automatically converts anyValue to a string when strType is
REG_SZ or REG_EXPAND_SZ. If strType is REG_DWORD, anyValue is
converted to an integer. If strType is REG_BINARY, anyValue must be an
integer.
Example
The following example writes a value and key entry into the
registry:
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.RegWrite "HKCU\ScriptEngine\Value", "Some string value"
WshShell.RegWrite "HKCU\ScriptEngine\Key\", 1 ,"REG_DWORD"
You can use the Windows API to accomplish what you need. Here's some general purpose code to read and write to the Registry:
Option Explicit
Private Sub Read_Click()
Text1.Text = ReadRegistry(HKEY_CURRENT_USER, "Software\Microsoft\Print\UnifiedPrintDialog", "PreferLegacyPrintDialog", ValDWord, "1")
End Sub
Private Sub Write_Click()
WriteRegistry HKEY_CURRENT_USER, "Software\Microsoft\Print\UnifiedPrintDialog", "PreferLegacyPrintDialog", ValDWord, Text1.Text
End Sub
In a Module place the following code:
Option Explicit
Public Const HKEY_CLASSES_ROOT = &H80000000
Public Const HKEY_CURRENT_USER = &H80000001
Public Const HKEY_LOCAL_MACHINE = &H80000002
Public Const HKEY_USERS = &H80000003
Public Const HKEY_PERFORMANCE_DATA = &H80000004
Public Const REG_SZ = 1
Public Const REG_DWORD = 4
Public Enum InTypes
ValNull = 0
ValString = 1
ValXString = 2
ValBinary = 3
ValDWord = 4
ValLink = 6
ValMultiString = 7
ValResList = 8
End Enum
Private Const ERROR_SUCCESS = 0&
Private Declare Function RegCloseKey Lib "advapi32.dll" (ByVal hKey As Long) As Long
Private Declare Function RegCreateKey Lib "advapi32.dll" Alias "RegCreateKeyA" (ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long
Private Declare Function RegOpenKey Lib "advapi32.dll" Alias "RegOpenKeyA" (ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long
Private Declare Function RegQueryValueEx Lib "advapi32.dll" Alias "RegQueryValueExA" (ByVal hKey As Long, ByVal lpValueName As String, ByVal lpReserved As Long, lpType As Long, lpData As Any, lpcbData As Long) As Long
Private Declare Function RegSetValueEx Lib "advapi32.dll" Alias "RegSetValueExA" (ByVal hKey As Long, ByVal lpValueName As String, ByVal Reserved As Long, ByVal dwType As Long, lpData As Any, ByVal cbData As Long) As Long
Public Function ReadRegistry(ByVal Group As Long, ByVal Section As String, ByVal Key As String, ByVal ValType As InTypes, Optional Default As Variant) As Variant
If ValType = ValString Then
ReadRegistry = ReadString(Group, Section, Key)
If ReadRegistry = "" Then ReadRegistry = Default
ElseIf ValType = ValDWord Then
ReadRegistry = ReadDword(Group, Section, Key)
If ReadRegistry = 0 Then ReadRegistry = Default
End If
End Function
Public Sub WriteRegistry(ByVal Group As Long, ByVal Section As String, ByVal Key As String, ByVal ValType As InTypes, ByVal Value As Variant)
If ValType = ValString Then
WriteString Group, Section, Key, CStr(Value)
ElseIf ValType = ValDWord Then
WriteDword Group, Section, Key, CLng(Value)
End If
End Sub
Private Function ReadString(hKey As Long, strPath As String, strValue As String) As String
Dim keyhand As Long
Dim lResult As Long
Dim strBuf As String
Dim lDataBufSize As Long
Dim intZeroPos As Integer
Dim lValueType As Long
Dim r As Long
r = RegOpenKey(hKey, strPath, keyhand)
lResult = RegQueryValueEx(keyhand, strValue, 0&, lValueType, ByVal 0&, lDataBufSize)
strBuf = String(lDataBufSize, " ")
lResult = RegQueryValueEx(keyhand, strValue, 0&, 0&, ByVal strBuf, lDataBufSize)
If lResult = ERROR_SUCCESS Then
intZeroPos = InStr(strBuf, Chr$(0))
If intZeroPos > 0 Then
ReadString = Left$(strBuf, intZeroPos - 1)
Else
ReadString = strBuf
End If
End If
End Function
Private Sub WriteString(hKey As Long, strPath As String, strValue As String, strdata As String)
Dim keyhand As Long
Dim r As Long
r = RegCreateKey(hKey, strPath, keyhand)
r = RegSetValueEx(keyhand, strValue, 0, REG_SZ, ByVal strdata, Len(strdata))
r = RegCloseKey(keyhand)
End Sub
Private Function ReadDword(ByVal hKey As Long, ByVal strPath As String, ByVal strValueName As String) As Long
Dim lResult As Long
Dim lValueType As Long
Dim lBuf As Long
Dim lDataBufSize As Long
Dim r As Long
Dim keyhand As Long
r = RegOpenKey(hKey, strPath, keyhand)
lDataBufSize = 4
lResult = RegQueryValueEx(keyhand, strValueName, 0&, lValueType, lBuf, lDataBufSize)
If lResult = ERROR_SUCCESS Then
If lValueType = REG_DWORD Then ReadDword = lBuf
End If
r = RegCloseKey(keyhand)
End Function
Private Sub WriteDword(ByVal hKey As Long, ByVal strPath As String, ByVal strValueName As String, ByVal lData As Long)
Dim keyhand As Long
Dim r As Long
r = RegCreateKey(hKey, strPath, keyhand)
r = RegSetValueEx(keyhand, strValueName, 0&, REG_DWORD, lData, 4)
r = RegCloseKey(keyhand)
End Function
I'm investigating a memory leak in some old VB6 code that seems to be related to recordset objects, so I'm trying to get the reference counts on the objects. I found some code online that will give a count of references to an object, and it works for a home-grown class. But when I try to apply it to ADODB recordset objects, the count is always 1492925242. I've tried this in the existing app and then in a dummy app - always comes back with the same number (unless there are no references, then it's 0).
Here's the code that gets the reference count:
Private Declare Sub RtlMoveMemory Lib "kernel32" (dest As Any, src As Any, ByVal nbytes As Long)
Function objRefCnt(obj As IUnknown) As Long
If Not obj Is Nothing Then
RtlMoveMemory objRefCnt, ByVal ObjPtr(obj) + 4, 4
objRefCnt = objRefCnt - 2
Else
objRefCnt = 0
End If
End Function
Here's the code that calls it on ADODB recordsets:
Sub main()
Dim obj_1 As ADODB.Recordset
Dim obj_2 As ADODB.Recordset
Debug.Print objRefCnt(obj_1) ' 0
Set obj_1 = New ADODB.Recordset
Debug.Print objRefCnt(obj_1) ' 1
Set obj_2 = obj_1
Debug.Print objRefCnt(obj_1) ' 2
Debug.Print objRefCnt(obj_2) ' 2
Set obj_2 = New ADODB.Recordset
Debug.Print objRefCnt(obj_1) ' 1
Debug.Print objRefCnt(obj_2) ' 1
End Sub
This returns the following:
0
1492925242
1492925242
1492925242
1492925242
1492925242
But when I added a dummy class called Class1 that has a single property (an integer), and create obj_1 and obj_2 as Class1 objects, I get this:
0
1
2
2
1
1
Any ideas on how I can get a reference count on the ADODB recordsets?
Thanks in advance.
The code you found assumes the reference count is stored inside the object at offset 4. There is no such requirement. IUnknown defines methods, not where private variables must be stored (and the reference count is a private variable of an object).
The way to get the reference count (for testing purposes only) is to call IUnknown.Release.
In order to do that from VB6, find olelib.tlb on the Internet (Edanmo's OLE interfaces & functions), reference it, and have
Public Function GetRefCount(ByVal obj As olelib.IUnknown) As Long
obj.AddRef
GetRefCount = obj.Release - 2
End Function
Dim r1 As ADODB.Recordset
Dim r2 As ADODB.Recordset
Set r1 = New ADODB.Recordset
Set r2 = r1
MsgBox GetRefCount(r1) ' 2
It appears m_dwRefCount member variable of ADODB.Recordset instances is at offset 16.
Try this objRefCnt replacement:
Private Declare Sub RtlMoveMemory Lib "kernel32" (dest As Any, src As Any, ByVal nbytes As Long)
Function RecordsetRefCnt(rs As Recordset) As Long
If Not rs Is Nothing Then
RtlMoveMemory RecordsetRefCnt, ByVal ObjPtr(rs) + 16, 4
RecordsetRefCnt = RecordsetRefCnt - 1
Else
RecordsetRefCnt = 0
End If
End Function
JFYI, here is a AddRef/Release based GetRefCount impl without additional typelibs
Private Declare Function DispCallFunc Lib "oleaut32" (ByVal pvInstance As Long, ByVal oVft As Long, ByVal lCc As Long, ByVal vtReturn As VbVarType, ByVal cActuals As Long, prgVt As Any, prgpVarg As Any, pvargResult As Variant) As Long
Public Function GetRefCount(pUnk As IUnknown) As Long
Const CC_STDCALL As Long = 4
Dim vResult As Variant
Call DispCallFunc(ObjPtr(pUnk), 1 * 4, CC_STDCALL, vbLong, 0, ByVal 0, ByVal 0, 0)
Call DispCallFunc(ObjPtr(pUnk), 2 * 4, CC_STDCALL, vbLong, 0, ByVal 0, ByVal 0, vResult)
GetRefCount = vResult - 2
End Function
And here is the AddRef/Release based GetRefCount implementation without additional typelibs which also works with 64-bit VBA:
#If VBA7 Then
Private Declare PtrSafe Function DispCallFunc Lib "oleAut32.dll" (ByVal pvInstance As LongPtr, ByVal oVft As LongPtr, ByVal cc As Long, ByVal vtReturn As VbVarType, ByVal cActuals As Long, ByRef prgVt As Any, ByRef prgpVarg As Any, ByRef pvargResult As Variant) As Long
#Else
Private Declare Function DispCallFunc Lib "oleaut32.dll" (ByVal pvInstance As Long, ByVal oVft As Long, ByVal cc As Long, ByVal vtReturn As VbVarType, ByVal cActuals As Long, ByRef prgVt As Any, ByRef prgpVarg As Any, ByRef pvargResult As Variant) As Long
#End If
Public Function GetRefCount(ByRef pUnk As IUnknown) As Long
Const CC_STDCALL As Long = 4
#If Win64 Then
Const PTR_SIZE As Long = 8
#Else
Const PTR_SIZE As Long = 4
#End If
If pUnk Is Nothing Then Exit Function
Dim vResult As Variant
Call DispCallFunc(ObjPtr(pUnk), 1 * PTR_SIZE, CC_STDCALL, vbLong, 0, ByVal 0, ByVal 0, 0)
Call DispCallFunc(ObjPtr(pUnk), 2 * PTR_SIZE, CC_STDCALL, vbLong, 0, ByVal 0, ByVal 0, vResult)
GetRefCount = vResult - 2
End Function
What i want :
to a make a button that exports the selected data in this FelxGrid into .ini file format take (heights) as section and the others as values and keys , it dosen't have to be ini format it can also be something close to it
What i tried so far
Private Sub commandbutton_1()
Dim configfile As String
Dim myArray() As String 'i tried using arry but it didn't work
configfile = "C:\" & "\CONFIGMEEE!.INI"
PutINISetting "", "", SettingsGrid.Clip, configfile
MsgBox "Exported.", vbInformation, "Settings"
SettingsGrid.SaveGrid configfile, flexFileTabText
What happened then
the data we exported but not formatted at all as ini and written so :
Important to know
The flexgrid iam using is a vsflexgrid not an msflexgrid
And i am also using this as a MOUDLE
'API Function to write information to the INI File
Private Declare Function WritePrivateProfileString Lib "kernel32" _
Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, _
ByVal lpKeyName As Any, _
ByVal lpString As Any, _
ByVal lpFileName As String) As Long
'Get the INI Setting from the File
Public Function GetINISetting(ByVal sHeading As String, _
ByVal sKey As String, _
sINIFileName) As String
Const cparmLen = 50
Dim sReturn As String * cparmLen
Dim sDefault As String * cparmLen
Dim lLength As Long
lLength = GetPrivateProfileString(sHeading, _
sKey, _
sDefault, _
sReturn, _
cparmLen, _
sINIFileName)
GetINISetting = Mid(sReturn, 1, lLength)
End Function
'Save INI Setting in the File
Public Function PutINISetting(ByVal sHeading As String, _
ByVal sKey As String, _
ByVal sSetting As String, _
sINIFileName) As Boolean
Const cparmLen = 50
Dim sReturn As String * cparmLen
Dim sDefault As String * cparmLen
Dim aLength As Long
aLength = WritePrivateProfileString(sHeading, _
sKey, _
sSetting, _
sINIFileName)
PutINISetting = True
End Function
Option Explicit
Public Sub save_url_contents_as_text()
Dim MyUrl As String
Dim MyFile As Object 'store the text file here
Dim tempstring As String
MyUrl = "www.AnythingIWantToPutHere"
'I want your help here. Something Like a function
tempstring = geturltext(MyUrl)
'I want to save the URL text contents here
MyFile = tempstring
End Sub
Taken directly from here. Change the URL and the filename as desired. This call writes the contents of the URL to a disk file.
This example shows how to use the URLDownloadToFile API function to download a file from a URL into a file in Visual Basic 6.
Private Declare Function URLDownloadToFile Lib "urlmon" _
Alias "URLDownloadToFileA" (ByVal pCaller As Long, _
ByVal szURL As String, ByVal szFileName As String, _
ByVal dwReserved As Long, ByVal lpfnCB As Long) As Long
Private Sub Form_Load()
' Download the file.
URLDownloadToFile 0, _
"http://www.vb-helper.com/vbhelper_425_64.gif", _
"C:\vbhelper_425_64.gif", 0, 0
End Sub
I am trying to save an image from a webpage using excel vba.
I'm managed to get the string (although not the one I want), and need to save it to disk.
The HTML code for the source is:
<img id="SkuPageMainImg" data-sku="491215" alt="Papir ubleket kraft 60g 40cm 5kg/rull" class="skuImageSTD" src="/content/images/product/491215_1_xnm.jpg?v=4TWLBni1V4k8GV8B_0P-GA" data-zoomimage="//www.staples.no/content/images/product/491215_1_xnl.jpg" data-resizeimage="{"0to1024":"/content/images/product/491215_1_xnm.jpg?v=4TWLBni1V4k8GV8B_0P-GA","1025to1450":"//www.staples.no/content/images/product/491215_1"}" data-screensize="">
My code is: IMG = .document.getElementById("SkuPageMainImg").src
This code captures the url after the src= :
/content/images/product/491215_1_xnm.jpg?v=4TWLBni1V4k8GV8B_0P-GA"
This will do, but what i would preffer to catch is the url after data-zoomimage= :
"//www.staples.no/content/images/product/491215_1_xnl.jpg"
Either way, what I am looking to accomplish is having Excel VBA save the image to a file on my disk - typically c:\folder\image_name.jpg
Anybody know the code to do this?
Import the URLDownloadToFile function and use it directly. The following is an entire module code sheet, including the declarations section at the top. The routine expects a list of the full img src URLs in column A starting at row 2. e.g.: http://www.staples.no/content/images/product/491215_1_xnm.jpg
Option Explicit
#If VBA7 And Win64 Then
Private Declare PtrSafe Function URLDownloadToFile Lib "urlmon" _
Alias "URLDownloadToFileA" ( _
ByVal pCaller As LongPtr, _
ByVal szURL As String, _
ByVal szFileName As String, _
ByVal dwReserved As LongPtr, _
ByVal lpfnCB As LongPtr _
) As Long
Private Declare PtrSafe Function DeleteUrlCacheEntry Lib "Wininet.dll" _
Alias "DeleteUrlCacheEntryA" ( _
ByVal lpszUrlName As String _
) As Long
#Else
Private Declare Function URLDownloadToFile Lib "urlmon" _
Alias "URLDownloadToFileA" ( _
ByVal pCaller As Long, _
ByVal szURL As String, _
ByVal szFileName As String, _
ByVal dwReserved As Long, _
ByVal lpfnCB As Long _
) As Long
Private Declare Function DeleteUrlCacheEntry Lib "Wininet.dll" _
Alias "DeleteUrlCacheEntryA" ( _
ByVal lpszUrlName As String _
) As Long
#End If
Public Const ERROR_SUCCESS As Long = 0
Public Const BINDF_GETNEWESTVERSION As Long = &H10
Public Const INTERNET_FLAG_RELOAD As Long = &H80000000
Sub dlStaplesImages()
Dim rw As Long, lr As Long, ret As Long, sIMGDIR As String, sWAN As String, sLAN As String
sIMGDIR = "c:\folder"
If Dir(sIMGDIR, vbDirectory) = "" Then MkDir sIMGDIR
With ActiveSheet '<-set this worksheet reference properly!
lr = .Cells(Rows.Count, 1).End(xlUp).Row
For rw = 2 To lr
sWAN = .Cells(rw, 1).Value2
sLAN = sIMGDIR & Chr(92) & Trim(Right(Replace(sWAN, Chr(47), Space(999)), 999))
Debug.Print sWAN
Debug.Print sLAN
If CBool(Len(Dir(sLAN))) Then
Call DeleteUrlCacheEntry(sLAN)
Kill sLAN
End If
ret = URLDownloadToFile(0&, sWAN, sLAN, BINDF_GETNEWESTVERSION, 0&)
.Cells(rw, 2) = ret
Next rw
End With
End Sub
A value of 0 is column B indicates success (e.g. ERROR_SUCCESS).