[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.vb.general.discussion

Storing ShellLinks as SQLite blobs

Rob

3/5/2011 7:37:00 AM

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
14 Answers

Peter T

2/8/2010 8:08:00 PM

0

Well, we wouldn't want anything remotely "budget" in Excel would we!

You can get the relative screen position of any cell with
PointsToScreenPixelsX & 'Y. Apart from the mouse coordinates, which I
assume you already know how to get, you'll need to factor in
'points-per-pixel' (typically 0.75) and Zoom.

It gets a bit more complicated if there are multiple panes (freeze panes)
but PointsToScreenPixelsX/Y now works with the 'Pane' object, assuming you
know which pane you'll be dealing with, if applicable.

Only other thing you need to figure for your needs is how to trap the mouse
click. Easiest would be in the selection event, which might mean you need to
use WithEvents to trap the sheet events (unless of course your app is only
geared to work in a given workbook).

Regards,
Peter T


"Andrew" <hooksie2@hotmail.com> wrote in message
news:55ddb035-86a2-49e0-b3a0-6114d67dbcda@j31g2000yqa.googlegroups.com...
Indeed - if I use the selected cell coordinates the inserted picture/
shape can be almost as much as the width of the cell away from the
point where the user really wanted the insert to occur. It's not the
end of the world but does appear a bit "budget".

Thanks


On 8 Feb, 16:05, "Peter T" <peter_t@discussions> wrote:
> Either I'm missing something or you've already got the information you
> need.
> You say user clicks on the worksheet so presumably that activates a cell -
> what more do you need than that. IOW why do you need the mouse coordinates
> when you've already got the cell coordinates, which is what you will be
> using to position your inserted shape.
>
> Or, wondering, do you want the exact spot within some cell rather than say
> the top/left cell coordinate.
>
> Regards,
> Peter T
>
> "Andrew" <hooks...@hotmail.com> wrote in message
>
> news:274023f9-7a21-4760-8b2b-894793c8c04d@a32g2000yqm.googlegroups.com...
> Hi Peter,
>
> Thanks for for the reply.
>
> I have a series of buttons displayed on the Ribbon which should insert
> a picture at a location selected by the user (by clicking on the
> worksheet). I need to be able to translate the mouse location to the
> appropriate sheet coordinates in order to insert the picture at the
> right spot.
>
> Thanks again,
> Andrew
>
> On 8 Feb, 15:21, "Peter T" <peter_t@discussions> wrote:
>
>
>
> > That approach doesn't work in 2007+ as embedded charts are not windows
> > in
> > they way they were in previous versions.
>
> > There are other ways of relating mouse coordinates to a cell address, or
> > a
> > cell position to screen coordinates depending on the overall objective.
>
> > Regards,
> > Peter T
>
> > "Andrew" <hooks...@hotmail.com> wrote in message
>
> >news:8fe07898-c265-4000-9cab-f2ce31f08cf6@l26g2000yqd.googlegroups.com...
>
> > > Some years ago I remember reading an approach for determining the
> > > mouse position within a sheet. I believe this used the GetCursorPos
> > > API to find the "absolute" mouse position relative to the window, then
> > > inserted a dummy chart object in cell A1, set a handle to this and
> > > then compared the coordinates of the chart to the mouse position to
> > > determine its relative position on the sheet. I've spent about an
> > > hour now searching for this code without success - does anyone have a
> > > copy they could re-post?
>
> > > Thanks a lot,
> > > Andrew- Hide quoted text -
>
> > - Show quoted text -- Hide quoted text -
>
> - Show quoted text -


Peter T

2/9/2010 6:34:00 PM

0

You don't need to be concerned with working out the distance to (say) the
top-left corner of A1 by taking into account QAT dim's, header sizes, is the
workbook window maximized or not, etc. But there's no need, as I mentioned
PointsToScreenPixelsX does it for you, albeit you have to factor in the
other adjustments I mentioned. If anything PointsToScreenPixelsX works
better in 2007 as it now works with Panes.

If you get stuck I'll put a demo together and forward.

Regards,
Peter T

"Andrew" <hooksie2@hotmail.com> wrote in message
news:1372c3cc-1e76-424c-9955-4e5306284c6a@d37g2000yqa.googlegroups.com...
I think the problem is knowing the amount of space taken up by the
ribbon and QAT at the top of the window. GetCursorPostion will return
coordinates relative to the window but shape objects are placed
relative to the worksheet area (0,0 at the top of cell A1). Although
the conversion from points to pixels is a necessary step I don't think
it's enough. Am I mis-interpreting you? I'm not clear how I could
get the relative screen position of a cell using
PointsToScreenPixelsX?

Thanks again,
Andrew


On 8 Feb, 20:07, "Peter T" <peter_t@discussions> wrote:
> Well, we wouldn't want anything remotely "budget" in Excel would we!
>
> You can get the relative screen position of any cell with
> PointsToScreenPixelsX & 'Y. Apart from the mouse coordinates, which I
> assume you already know how to get, you'll need to factor in
> 'points-per-pixel' (typically 0.75) and Zoom.
>
> It gets a bit more complicated if there are multiple panes (freeze panes)
> but PointsToScreenPixelsX/Y now works with the 'Pane' object, assuming you
> know which pane you'll be dealing with, if applicable.
>
> Only other thing you need to figure for your needs is how to trap the
> mouse
> click. Easiest would be in the selection event, which might mean you need
> to
> use WithEvents to trap the sheet events (unless of course your app is only
> geared to work in a given workbook).
>
> Regards,
> Peter T
>
> "Andrew" <hooks...@hotmail.com> wrote in message
>
> news:55ddb035-86a2-49e0-b3a0-6114d67dbcda@j31g2000yqa.googlegroups.com...
> Indeed - if I use the selected cell coordinates the inserted picture/
> shape can be almost as much as the width of the cell away from the
> point where the user really wanted the insert to occur. It's not the
> end of the world but does appear a bit "budget".
>
> Thanks
>
> On 8 Feb, 16:05, "Peter T" <peter_t@discussions> wrote:
>
>
>
> > Either I'm missing something or you've already got the information you
> > need.
> > You say user clicks on the worksheet so presumably that activates a
> > cell -
> > what more do you need than that. IOW why do you need the mouse
> > coordinates
> > when you've already got the cell coordinates, which is what you will be
> > using to position your inserted shape.
>
> > Or, wondering, do you want the exact spot within some cell rather than
> > say
> > the top/left cell coordinate.
>
> > Regards,
> > Peter T
>
> > "Andrew" <hooks...@hotmail.com> wrote in message
>
> >news:274023f9-7a21-4760-8b2b-894793c8c04d@a32g2000yqm.googlegroups.com...
> > Hi Peter,
>
> > Thanks for for the reply.
>
> > I have a series of buttons displayed on the Ribbon which should insert
> > a picture at a location selected by the user (by clicking on the
> > worksheet). I need to be able to translate the mouse location to the
> > appropriate sheet coordinates in order to insert the picture at the
> > right spot.
>
> > Thanks again,
> > Andrew
>
> > On 8 Feb, 15:21, "Peter T" <peter_t@discussions> wrote:
>
> > > That approach doesn't work in 2007+ as embedded charts are not windows
> > > in
> > > they way they were in previous versions.
>
> > > There are other ways of relating mouse coordinates to a cell address,
> > > or
> > > a
> > > cell position to screen coordinates depending on the overall
> > > objective.
>
> > > Regards,
> > > Peter T
>
> > > "Andrew" <hooks...@hotmail.com> wrote in message
>
> > >news:8fe07898-c265-4000-9cab-f2ce31f08cf6@l26g2000yqd.googlegroups.com...
>
> > > > Some years ago I remember reading an approach for determining the
> > > > mouse position within a sheet. I believe this used the GetCursorPos
> > > > API to find the "absolute" mouse position relative to the window,
> > > > then
> > > > inserted a dummy chart object in cell A1, set a handle to this and
> > > > then compared the coordinates of the chart to the mouse position to
> > > > determine its relative position on the sheet. I've spent about an
> > > > hour now searching for this code without success - does anyone have
> > > > a
> > > > copy they could re-post?
>
> > > > Thanks a lot,
> > > > Andrew- Hide quoted text -
>
> > > - Show quoted text -- Hide quoted text -
>
> > - Show quoted text -- Hide quoted text -
>
> - Show quoted text -


Peter T

2/10/2010 1:29:00 PM

0

I think you may be missing one or two things (not sure), in essence the
position of the mouse pointer in points from the top-left corner of the
sheet is

CursorPixelsX - PointsToScreenPixelsX(0) * ppp * zoom%

where CursorPixelsX is returned from 'GetCursorPos' and ppp refers to
'Points-per-Pixel' typically 0.75 but confirmed with a few API calls.

There are one or two other things that might also need to be taken into
account. Having had another look at some old stuff I should be able to post
a simple demo here later today, rather than something needing to be wrapped
in a workbook.

Regards,
Peter T


"Andrew" <hooksie2@hotmail.com> wrote in message
news:93757c4d-9623-42e7-8862-f958ed6a39fb@19g2000yql.googlegroups.com...
Finally the penny drops ... thanks for sticking with me on this one!

This is what I'm now doing and it seems to work beautifully:

1) Call GetCursorPos to find mouse position (returned as pixels - I
think)
2) Get X (left) and Y (top) coordinates of cell A1 which are returned
in points
3) Convert cell coordinates to screen pixels using
ActiveWindow.PointsToPixelsX/Y
4) Subtract cell coordinates from mouse position coordinates to get
position relative to the sheet in pixels (zoom=100%)
5) Convert back to points and divide by Window Zoom

I need to tidy the whole thing up but once I'm fully happy with it
I'll post back in case anyone else is interested.

Thanks again for your help.
Andrew

On 9 Feb, 18:34, "Peter T" <peter_t@discussions> wrote:
> You don't need to be concerned with working out the distance to (say) the
> top-left corner of A1 by taking into account QAT dim's, header sizes, is
> the
> workbook window maximized or not, etc. But there's no need, as I mentioned
> PointsToScreenPixelsX does it for you, albeit you have to factor in the
> other adjustments I mentioned. If anything PointsToScreenPixelsX works
> better in 2007 as it now works with Panes.
>
> If you get stuck I'll put a demo together and forward.
>
> Regards,
> Peter T
>
> "Andrew" <hooks...@hotmail.com> wrote in message
>
> news:1372c3cc-1e76-424c-9955-4e5306284c6a@d37g2000yqa.googlegroups.com...
> I think the problem is knowing the amount of space taken up by the
> ribbon and QAT at the top of the window. GetCursorPostion will return
> coordinates relative to the window but shape objects are placed
> relative to the worksheet area (0,0 at the top of cell A1). Although
> the conversion from points to pixels is a necessary step I don't think
> it's enough. Am I mis-interpreting you? I'm not clear how I could
> get the relative screen position of a cell using
> PointsToScreenPixelsX?
>
> Thanks again,
> Andrew
>
> On 8 Feb, 20:07, "Peter T" <peter_t@discussions> wrote:
>
>
>
> > Well, we wouldn't want anything remotely "budget" in Excel would we!
>
> > You can get the relative screen position of any cell with
> > PointsToScreenPixelsX & 'Y. Apart from the mouse coordinates, which I
> > assume you already know how to get, you'll need to factor in
> > 'points-per-pixel' (typically 0.75) and Zoom.
>
> > It gets a bit more complicated if there are multiple panes (freeze
> > panes)
> > but PointsToScreenPixelsX/Y now works with the 'Pane' object, assuming
> > you
> > know which pane you'll be dealing with, if applicable.
>
> > Only other thing you need to figure for your needs is how to trap the
> > mouse
> > click. Easiest would be in the selection event, which might mean you
> > need
> > to
> > use WithEvents to trap the sheet events (unless of course your app is
> > only
> > geared to work in a given workbook).
>
> > Regards,
> > Peter T
>
> > "Andrew" <hooks...@hotmail.com> wrote in message
>
> >news:55ddb035-86a2-49e0-b3a0-6114d67dbcda@j31g2000yqa.googlegroups.com...
> > Indeed - if I use the selected cell coordinates the inserted picture/
> > shape can be almost as much as the width of the cell away from the
> > point where the user really wanted the insert to occur. It's not the
> > end of the world but does appear a bit "budget".
>
> > Thanks
>
> > On 8 Feb, 16:05, "Peter T" <peter_t@discussions> wrote:
>
> > > Either I'm missing something or you've already got the information you
> > > need.
> > > You say user clicks on the worksheet so presumably that activates a
> > > cell -
> > > what more do you need than that. IOW why do you need the mouse
> > > coordinates
> > > when you've already got the cell coordinates, which is what you will
> > > be
> > > using to position your inserted shape.
>
> > > Or, wondering, do you want the exact spot within some cell rather than
> > > say
> > > the top/left cell coordinate.
>
> > > Regards,
> > > Peter T
>
> > > "Andrew" <hooks...@hotmail.com> wrote in message
>
> > >news:274023f9-7a21-4760-8b2b-894793c8c04d@a32g2000yqm.googlegroups.com...
> > > Hi Peter,
>
> > > Thanks for for the reply.
>
> > > I have a series of buttons displayed on the Ribbon which should insert
> > > a picture at a location selected by the user (by clicking on the
> > > worksheet). I need to be able to translate the mouse location to the
> > > appropriate sheet coordinates in order to insert the picture at the
> > > right spot.
>
> > > Thanks again,
> > > Andrew
>
> > > On 8 Feb, 15:21, "Peter T" <peter_t@discussions> wrote:
>
> > > > That approach doesn't work in 2007+ as embedded charts are not
> > > > windows
> > > > in
> > > > they way they were in previous versions.
>
> > > > There are other ways of relating mouse coordinates to a cell
> > > > address,
> > > > or
> > > > a
> > > > cell position to screen coordinates depending on the overall
> > > > objective.
>
> > > > Regards,
> > > > Peter T
>
> > > > "Andrew" <hooks...@hotmail.com> wrote in message
>
> > > >news:8fe07898-c265-4000-9cab-f2ce31f08cf6@l26g2000yqd.googlegroups.com...
>
> > > > > Some years ago I remember reading an approach for determining the
> > > > > mouse position within a sheet. I believe this used the
> > > > > GetCursorPos
> > > > > API to find the "absolute" mouse position relative to the window,
> > > > > then
> > > > > inserted a dummy chart object in cell A1, set a handle to this and
> > > > > then compared the coordinates of the chart to the mouse position
> > > > > to
> > > > > determine its relative position on the sheet. I've spent about an
> > > > > hour now searching for this code without success - does anyone
> > > > > have
> > > > > a
> > > > > copy they could re-post?
>
> > > > > Thanks a lot,
> > > > > Andrew- Hide quoted text -
>
> > > > - Show quoted text -- Hide quoted text -
>
> > > - Show quoted text -- Hide quoted text -
>
> > - Show quoted text -- Hide quoted text -
>
> - Show quoted text -


Peter T

2/10/2010 4:12:00 PM

0

Put the following into ThisWorkbook and Normal modules as indicated.
Hold Ctrl and Right-click to center "TheSun" under the cursor

''' ThisWorkbook module

Option Explicit
Private Declare Function GetKeyState32 Lib "user32" _
Alias "GetKeyState" (ByVal vKey As Integer) As Integer


Private Sub Workbook_SheetBeforeRightClick(ByVal Sh As Object, _
ByVal Target As Range, Cancel As Boolean)
Dim bCtrl As Long

' >>> Right-click and hold Ctrl <<<

' is Ctrl pressed
bCtrl = GetKeyState32(vbKeyControl) < 0

If bCtrl Then
Cancel = True ' prevent the rt-click menu
TestCursorToPoints Sh
End If

End Sub

''' end ThisWorkbook module

''' code in normal module

Option Explicit
''' pmbthornton at gmail dot com

' re points per pixel
Private Const LOGPIXELSX As Long = 88&
Private Const POINTS_PER_INCH As Long = 72&
Private Declare Function GetDC Lib "user32" ( _
ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" ( _
ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" ( _
ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Declare Function GetDesktopWindow Lib "user32" () As Long

' re cursor position
Private Type POINTAPI
X As Long
Y As Long
End Type
Private Declare Function GetCursorPos Lib "user32.dll" ( _
ByRef lpPoint As POINTAPI) As Long

Private mPPP As Single ' points per pixel

Function CursorToPoints(X As Single, Y As Single) As Long
Dim x0 As Single, y0 As Single
Dim zm As Single
Dim rngCursor As Range
Dim pta As POINTAPI

On Error GoTo errH

If mPPP = 0 Then getPPP

Call GetCursorPos(pta)

With ActiveWindow

If .Panes.Count = 1 Then
x0 = .PointsToScreenPixelsX(0)
y0 = .PointsToScreenPixelsY(0)

ElseIf Val(Application.Version) >= 12 Then

With .Panes(.Panes.Count)
x0 = .PointsToScreenPixelsX(0)
y0 = .PointsToScreenPixelsY(0)
End With
Else
Err.Raise 10100, , _
"To do: cater for Freeze Panes in 2000-2003"
End If

If x0 = 0 And y0 = 0 Then
Err.Raise 10200, , _
"At least part of the worksheet must be in view"
End If

zm = 100 / .Zoom

X = (pta.X - x0) * mPPP * zm
Y = (pta.Y - y0) * mPPP * zm

On Error Resume Next
' attempt to return the cell under the cursor
' btw, if only need to return the cell under the mouse
' this is all that's required
Set rngCursor = .RangeFromPoint(pta.X, pta.Y)
On Error GoTo errH

End With

If Not rngCursor Is Nothing Then

If rngCursor.Address = ActiveCell.Address Then
CursorToPoints = 2 ' mouse over activecell
Else
CursorToPoints = 1 ' mouse not over activecell
End If

ElseIf X < 0 Or Y < 0 Then
CursorToPoints = 0 ' mouse above or to left of visible cells
Else
CursorToPoints = -1 ' mouse to right or below visible cells
End If

Exit Function

errH:
MsgBox Err.Description, , "CursorToPoints"

End Function

Sub getPPP()
' get Points / Pixel
' typically ppp is 72/96 = 0.75 in systems with Normal Fonts
Dim hWin As Long
Dim dcDT As Long
Dim nDPI As Long

hWin = GetDesktopWindow
dcDT = GetDC(hWin)
nDPI = GetDeviceCaps(dcDT, LOGPIXELSX)
ReleaseDC hWin, dcDT
mPPP = POINTS_PER_INCH / nDPI

End Sub

''''''' Test code '''''''

Sub test()
TestCursorToPoints ActiveSheet
End Sub

Sub TestCursorToPoints(ws As Worksheet)
Dim bVis As Boolean, bCenter As Boolean
Dim res As Long
Dim X As Single, Y As Single

res = CursorToPoints(X, Y)

bVis = CBool(res)
bCenter = True

MoveTheSun ws, X, Y, bVis, bCenter

End Sub

Sub MoveTheSun(ws As Worksheet, X As Single, Y As Single, _
bVis As Boolean, bCenter As Boolean)
Dim nL As Single, nT As Single
Dim shp As Shape
Const cW As Single = 24, cH As Single = 24
Const cSUN As String = "TheSun"

nL = X
nT = Y
If bCenter Then
nL = nL - (cW / 2)
nT = nT - (cH / 2)
End If

On Error Resume Next
Set shp = ActiveSheet.Shapes(cSUN)
On Error GoTo 0

If shp Is Nothing Then
Set shp = ws.Shapes.AddShape(msoShapeSun, nL, nT, cW, cH)
shp.Fill.ForeColor.RGB = RGB(255, 240, 140)
shp.Line.ForeColor.RGB = RGB(255, 180, 0)
shp.Name = cSUN

Else
With shp
.Left = nL
.Top = nT
.Width = cW
.Height = cH
.Visible = bVis
End With
End If

End Sub


Regrds,
Peter T





Peter T

2/11/2010 11:58:00 AM

0

Ah, the brackets, how observant. Aircode I'm afraid but they were there by
intention!

Trust the demo worked, but please advise if anything not quite right.

Regards,
Peter T


"Andrew" <hooksie2@hotmail.com> wrote in message
news:ee8810d8-4425-4abd-8c18-d8b8dfae8591@z26g2000yqm.googlegroups.com...
> Embarrassingly I failed to compute that top of A1 is just 0!! Too
> busy thinking about everything else.
>
> BTW, there's a bracket missing in your expression below though.
> Should be:
> (CursorPixelsX - PointsToScreenPixelsX(0)) * ppp * zoom%
> since it's the distance from top left of A1 to the cursor which
> changes with zoom etc. (I know you know this since it is what you
> have in your code that you posted later).
>
> Thanks!
>
> On 10 Feb, 13:28, "Peter T" <peter_t@discussions> wrote:
>> I think you may be missing one or two things (not sure), in essence the
>> position of the mouse pointer in points from the top-left corner of the
>> sheet is
>>
>> CursorPixelsX - PointsToScreenPixelsX(0) * ppp * zoom%
>>
>> where CursorPixelsX is returned from 'GetCursorPos' and ppp refers to
>> 'Points-per-Pixel' typically 0.75 but confirmed with a few API calls.
>>
>> There are one or two other things that might also need to be taken into
>> account. Having had another look at some old stuff I should be able to
>> post
>> a simple demo here later today, rather than something needing to be
>> wrapped
>> in a workbook.
>>
>> Regards,
>> Peter T

<snip>


news.highwayone.net

3/5/2011 11:28:00 AM

0

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."

Rob

3/5/2011 2:43:00 PM

0

On Sat, 05 Mar 2011 07:37:15 +0000, Rob <rob@notvalid.com> wrote:

>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.

Well, I've answered one of my own questions.

One can write to the steam using IStream::Write but one must reset the
stream's seek pointer to the begining of the stream before calling
IpersistStream::Load

So loading a ShellLink from an array can be written like this:

Private Function ByteArrayToShellLink(b() As Byte) As CShellLink
Dim spstm As IVBStream
Dim cb As Long

Set ByteArrayToShellLink = New CShellLink

cb = UBound(b) - LBound(b) + 1

Call CreateStreamOnHGlobal(0, APITRUE, spstm)

With spstm
Call .SetSize(cb / 10000) 'Currency
Call .Write(b(LBound(b)), cb, ByVal pNull)
Call .Seek(0, 0)
End With

Call CPersistStream(ByteArrayToShellLink).Load(spstm)

End Function

Private Function CPersistStream(obj As IUnknown) As IVBPersistStream
Set CPersistStream = obj
End Function

news.highwayone.net

3/5/2011 3:39:00 PM

0

On Sat, 05 Mar 2011 14:42:32 -0000, Rob <rob@notvalid.com> wrote:

> On Sat, 05 Mar 2011 07:37:15 +0000, Rob <rob@notvalid.com> wrote:
>
>> 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.
>
> Well, I've answered one of my own questions.
>
> One can write to the steam using IStream::Write but one must reset the
> stream's seek pointer to the begining of the stream before calling
> IpersistStream::Load
>
> So loading a ShellLink from an array can be written like this:
>
> Private Function ByteArrayToShellLink(b() As Byte) As CShellLink
> Dim spstm As IVBStream
> Dim cb As Long
> Set ByteArrayToShellLink = New CShellLink
> cb = UBound(b) - LBound(b) + 1
>
> Call CreateStreamOnHGlobal(0, APITRUE, spstm)
> With spstm
> Call .SetSize(cb / 10000) 'Currency
> Call .Write(b(LBound(b)), cb, ByVal pNull)
> Call .Seek(0, 0)
> End With
> Call CPersistStream(ByteArrayToShellLink).Load(spstm)
>
> End Function
>
> Private Function CPersistStream(obj As IUnknown) As IVBPersistStream
> Set CPersistStream = obj
> End Function


Next time you wake me up, better be for some truly eficient code.

Better yet, one that won't stack overflow would suffice.

Let me rest you evil tortuous mind.

I can see you're enjoying VB. That's nice.

But in the end, all gets down to "keep it simple" as one should be.

I'm sure you've heard this before.


--
"Knowledge is not power. It's wisdom and truth. Power comes and goes,
while wisdom stays and grows."

Bob Butler

3/5/2011 4:19:00 PM

0


"zebra" <reply@newsgroup.pls> wrote in message
news:op.vrvbggfl08zx2x@localhost...
> On Sat, 05 Mar 2011 07:37:15 -0000, Rob <rob@notvalid.com> wrote:
<cut>
> Use "Option base 0" directive to avoy this exercise:
>
> ReDim b(0 To cb - 1)
>
> ... and do simply this:
>
> ReDim b(cb - 1)

Right, maiking code less self-documenting and self-contained and reliant on
external settings is always better.

> ... 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.

it wasn't being instantiated twice, just referenced twice and the With block
also references it twice but cleans up one automatically.

news.highwayone.net

3/5/2011 7:43:00 PM

0

On Sat, 05 Mar 2011 16:18:37 -0000, Bob Butler <bob_butler@cox.invalid>
wrote:

>
> "zebra" <reply@newsgroup.pls> wrote in message
> news:op.vrvbggfl08zx2x@localhost...
>> On Sat, 05 Mar 2011 07:37:15 -0000, Rob <rob@notvalid.com> wrote:
> <cut>
>> Use "Option base 0" directive to avoy this exercise:
>>
>> ReDim b(0 To cb - 1)
>>
>> ... and do simply this:
>>
>> ReDim b(cb - 1)
>
> Right, maiking code less self-documenting and self-contained and reliant
> on external settings is always better.
>

This is done at module/class level usualy near the "Option explicit" (also
a recomended practice).

It states that "this code uses the zero as the first ordinal of an array
element"

If it's new to you, don't call it less-documented, but less RTFM'ed.

But yeah, one can also do iNum = 1 + 1 + 1 + 1 + 1 + 1 + 1 instead of
iNum = 3 + 4 just to acertain that 1 is the unit.

Or totaly abolish the constants. Suits me.


>> ... 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.
>
> it wasn't being instantiated twice, just referenced twice and the With
> block also references it twice but cleans up one automatically.
>

Exactly. That's it. My bad. I do this verbal switching lot's of times.



--
"Knowledge is not power. It's wisdom and truth. Power comes and goes,
while wisdom stays and grows."