news.highwayone.net
3/5/2011 11:28:00 AM
On Sat, 05 Mar 2011 07:37:15 -0000, Rob <rob@notvalid.com> wrote:
> I'd like to store ShellLinks in an SQLite database without having to
> save or load them to a .lnk file.
>
> The dhRichClient3 wrapper for SQLite returns blobs as byte arrays,
> i.e. b() = rs.Fields("blob"), whereas the only way I know to load/save
> a ShellLink from/to memory is to use a Stream created with
> CreateStreamOnHGlobal so this means the data has to be copied an extra
> time.
>
> For example, at the end of this post there's some really quick and
> dirty code that creates a ShellLink, saves it to global memory, copies
> the global memory into a byte array and then does the whole thing in
> reverse.
>
> But I'd prefer not to have to copy the data more than I have to so I'm
> wondering is there any way to load and save to a byte array directly?
>
> Less importantly, when I was writing the code shown blow I initially
> tried to use IStream::Read and IStream::Write rather than CopyMemory
> to get the data to and from the byte array but I couldn't get it to
> work. The documentation states that the object returned from
> CreateStreamOnHGlobal supports reading and writing so am I right in
> thinking that it should be possible to do something like "call
> spstm.Write(b(0), cb, byval 0&)" to copy from the array to the memory
> spstm is created on and the reverse using spstm.read?
>
> I'm fairly new to both SQLite and OS Com objects so forgive me if
> these are stupid questions.
>
> Thanks in advance
> Rob
>
>
> '***** code *****
>
> '(note: uses Win.tlb unicode version)
>
> Option Explicit
>
> Private Declare Function CreateStreamOnHGlobal Lib "ole32" ( _
> ByVal hGlobal As Long, _
> ByVal fDeleteOnRelease As Long, _
> ppstm As IVBStream _
> ) As Long
>
> Private Sub Form_Load()
> Dim spsl As CShellLink
> Dim spps As IVBPersistStream
> Dim spstm As IVBStream
> Dim hGlob As Long
> Dim b() As Byte
> Dim cb As Long
> Dim sBuff As String
> Const FileName = "C:\install.exe"
> 'Create the ShellLink
> Set spsl = New CShellLink
> Call spsl.SetPath(FileName)
> 'get a glob to save to
> hGlob = GlobalAlloc(GMEM_MOVEABLE, 0)
> 'Save the ShellLink to glob
> Set spps = spsl
> Call CreateStreamOnHGlobal(hGlob, 0, spstm)
> Call spps.Save(spstm, APITRUE)
> 'make sure the byte array is big enough
> cb = GlobalSize(hGlob)
> ReDim b(0 To cb - 1)
> 'copy glob to byte array
> Call CopyMemory(b(0), ByVal GlobalLock(hGlob), cb)
> Call GlobalUnlock(hGlob)
> 'clean up
> Set spsl = Nothing
> Set spps = Nothing
> Set spstm = Nothing
> Call GlobalFree(hGlob)
> 'check that we've got something in the byte array
> Dim s As String, i As Long
> For i = LBound(b) To UBound(b)
> s = s & Right$("0" & Hex$(b(i)), 2)
> Next
> Debug.Print s
> 'try to recreate the shelllink
> Set spsl = New CShellLink
> 'get a glob of the right size
> cb = UBound(b) + 1
> hGlob = GlobalAlloc(GMEM_MOVEABLE, cb)
> 'copy the byte array into the glob
> Call CopyMemory(ByVal GlobalLock(hGlob), b(0), cb)
> Call GlobalUnlock(hGlob)
> 'load the glob into the shelllink
> Set spps = spsl
> Call CreateStreamOnHGlobal(hGlob, APIFALSE, spstm)
> Call spps.Load(spstm)
> 'check that ShellLink is valid
> sBuff = String$(MAX_PATH, 0)
>
> Call spsl.GetPath(sBuff, MAX_PATH, ByVal 0&, 0)
>
> Debug.Print "Path = " & Left$(sBuff, lstrlen(sBuff))
> 'clean up
> Set spsl = Nothing
> Set spps = Nothing
> Set spstm = Nothing
> Call GlobalFree(hGlob)
> End Sub
Rob,
First of, I need to sleep and so do you. Don't deny it. ;-)
Now:
Use "Option base 0" directive to avoy this exercise:
ReDim b(0 To cb - 1)
.... and do simply this:
ReDim b(cb - 1)
.... Now, cleaning up the code a bit more, doing this:
Set spsl = New CShellLink
Call spsl.SetPath(FileName)
Set spps = spsl
Call spps.Save(spstm, APITRUE)
.... as the same effect as only:
Set spsl = New CShellLink
With spsl
.SetPath(FileName)
.Save(spstm, APITRUE)
End With
.... since you don't use sspl anymore until you free it. So, this way
there's one less pointer (ssps), one less copy operation, unecessary
memory allocation and data duplication and you don't have to instanciate
the spsl object twice.
Now, something in my gut tells me that:
'copy glob to byte array
cb = GlobalSize(hGlob)
ReDim b(0 To cb - 1)
Call CopyMemory(b(0), ByVal GlobalLock(hGlob), cb)
Call GlobalUnlock(hGlob)
Call GlobalFree(hGlob)
.... unlocking the memory, flush it, traversing the whole array to check if
it has something instead of using "UBound(b) > -1" and then putting the
array back in the same place by doing again what was not needed to be
undone in the first place:
'copy the byte array into the glob
cb = UBound(b) + 1
hGlob = GlobalAlloc(GMEM_MOVEABLE, cb)
Call CopyMemory(ByVal GlobalLock(hGlob), b(0), cb)
Call GlobalUnlock(hGlob)
.... is something that it might be just a bit redundant. Hey! but that's
just me! that I'm a very redundant person, that's what kind of person I am.
And if your guts tell you the same, it sure means you're still alive.
Go out man, enjoy life & stuff.
:-)
'Nough cofee. Bed time. Nice seeing you.
--
"Knowledge is not power. It's wisdom and truth. Power comes and goes,
while wisdom stays and grows."