Eli mietin tässä, kun olen tekemässä peliä. Niin onko jotenkin mahdollista käydä jonkinnäköisellä foreach loopilla kaikki formin kontrollit ja muuttujat läpi
Silleen että saisin kaikista arvot talteen ja voisin kirjoittaa ne tiedostoon.
Kontrolleita on ihan image1, hscrollbar, label, checkbox, optionbutton, listbox, combobox jne jne
Muuttujatyyppejä on Integer, Long, Boolean sekä integeristä että longista taulukkoja lisäksi saattaa olla joitakin muita tyyppejä.
Vai pitääkö jokaisen arvo yksitellen kirjoittaa tiedostoon ja lukea + parsia sieltä.
On mahdollista, aika helpostikin.
Grez kirjoitti:
On mahdollista, aika helpostikin.
Heitäppäs esimerkkiä...
Okei tuon kontrollien arvojen tallennuksen keksin jo, mutta miten onnistuu muuttujien läpikäyminen?
No itse asiassa, en lukenut näköjään riittävän hyvin, kun en tajunnut että halusit myös ne muuttujat.
Julkiset muuttujat saisi varmaan enumeroituakin, mutta sisäisistä muuttujista VB6 ei taida tallentaa riittävästi tietoa ajonaikaiseen enumerointiin. Toki jos on vain noita mainitsemiasi muuttujatyyppejä, eikä esim. String tai dynaamisesti määriteltyjä taulukoita, niin saattaisi onnistua vaan ottaa ensimmäisen ja viimeisen muuttujan osoitteet ja tallentaa niiden väliin jäävä muistialue.
Suurinosa muuttujista on julkisia, miten käytännössä "enumroin"?
Voit rakentaa vaikka oman Typen, määrittää yhden muuttujan (se Type) jossa ne kaikki on määriteltynä ja tallentamisesta tulee huomattavasti helpompaa. Stringit tosin ovat vähän vaikeampia tallennettavia, niille on helpointa määrittää kiinteä pituus.
Typen eduksi tulee myös se, että kun kirjoitat muuttujan nimen ja pisteen, niin saat automaattisesti listan kaikista tallennettavista muuttujista.
Vielä kehittyneempää olisi rakentaa luokka, joka tekee periaatteessa saman, mutta joka sallisi joustavamman tiedostorakenteen (eli tavallaan jokainen tiedonosanen tallennettaisiin jollakin tietyllä tavalla, vaikkapa XML:nä, jotta tiedostoa voisi laajentaa helpommin ilman että pelin eri versioiden tallennukset menevät rikki käytettäessä eri versiota).
Heippa taas!
koskapa aihe alkoi kiinnostamaan niin päätin hieman tutkia moisen Save Settings viritelmän periaatetta VBA-perspektiivistä ja tutkimuksen tulos oli, että kontrollien ominaisuudet saa melko helposti kerättyä ja niputettua for each loopilla ja pukattua tekstitiedostoon lukuun ottamatta .picture- ominaisuutta sillä ominaisuuden takaisin tuominen tiedostosta ei onnistu luettaessa arvo suoraan kontrollin asetuksista eli se puoli on siis hoidettava erikseen…
Mitä tulee muuttujien arvojen keräämiseen ja tallentamiseen, niin nimimerkki: Merrin ehdottama Tyyppi on helppo rakentaa ja toimii suhteellisen hyvin jos Tyypin sisälle ei pukata taulukkoja…hieman harmittaa, etten pääse juuri nyt testaaman viritelmää VB6:lla, mutten silti aio enää asentaa sitä koneelleni…
Taikana viritelmässä on, että kerätyt ja tiedostoon tallennetut asetustiedot kirjoitetaan ohjelman latauksen yhteydessä VBA-projektin koodimoduulissa valmiin tapahtuman sisään ja tapahtuma laukaistaan lomakkeen aktivoituessa... Suljettaessa lomake poistetaan koodimoduulista sinne tiedostosta tuotu merkkijono lomakkeen QueryClose_tapahtumassa, jolloin myös kerätään senhetkiset asetustiedot ja tallennetaan tiedostoon...
Tässä mallissa olisi optimaalisinta, että merkkijonsta voisi muodostaa suoraan tapahtumakoodin ja suorittaa ladattaessa tiedostosta esim. Microsoft Script Controll'n avulla...testattuani aikani totesin, että kotrollinen ominaisuudet hoituvat em. kontrollin avulla hyvin, mutta lisättyäni peliin myös muuttujat ei scripti kontrolli kyennyt suoriutumaan koodista...
Dim fullPath As String
Dim ClRfRep As String
Private Type SettingType
Setting As String
End Type
Private Type SngVarType
int As Integer
lng As Long
sng As Single
dbl As Double
bool As Boolean
str As String
var As Variant
End Type
Private Settings(1) As SettingType
Private Variables() As SngVarType
Private Function GetCtlPropValues(frm As Variant) As String
Dim strRet As String
Dim ctl As Control
On Error GoTo Handler
For Each ctl In frm.Controls
With ctl
strRet = strRet & _
.Parent.Name & "." & .Name & ".Left = " & _
Replace(str(.Left), ",", ".") & vbCrLf & _
.Parent.Name & "." & .Name & ".Top = " & _
Replace(str(.Top), ",", ".") & vbCrLf & _
.Parent.Name & "." & .Name & ".Width = " & _
Replace(str(.Width), ",", ".") & vbCrLf & _
.Parent.Name & "." & .Name & ".Height = " & _
Replace(str(.Height), ",", ".") & vbCrLf & _
.Parent.Name & "." & .Name & ".Enabled = " _
& .Enabled & vbCrLf & _
.Parent.Name & "." & .Name & ".Visible = " _
& .Visible & vbCrLf & _
.Parent.Name & "." & .Name & ".ForeColor = " _
& str(.ForeColor) & vbCrLf & _
.Parent.Name & "." & .Name & ".BackColor = " _
& str(.BackColor) & vbCrLf
strRet = strRet & _
.Parent.Name & "." & .Name & ".Caption = " _
& Chr(34) & .Caption & Chr(34) & vbCrLf
strRet = strRet & _
.Parent.Name & "." & .Name & ".Text = " _
& Chr(34) & Replace(.Text, vbCrLf, ClRfRep) _
& Chr(34) & vbCrLf
strRet = strRet & _
.Parent.Name & "." & .Name & ".Checked = " _
& .Checked & vbCrLf
strRet = strRet & _
.Parent.Name & "." & .Name & ".Value = " _
& Replace(str(.Value), ",", ".") & vbCrLf
End With
Next
GetCtlPropValues = Replace(strRet, " ", " "): strRet = ""
Exit Function
Handler:
Err.Clear
Resume Next
End Function
Private Function GetSngVariables() As String
Dim SngVarStr As String
For i = LBound(Variables) To UBound(Variables)
With Variables(i)
SngVarStr = SngVarStr & _
"Variables(" & CStr(i) & ").bool = " _
& str(.bool) & vbCrLf & _
"Variables(" & CStr(i) & ").dbl = " _
& Trim(str(.dbl)) & vbCrLf & _
"Variables(" & CStr(i) & ").int = " _
& Trim(str(.int)) & vbCrLf & _
"Variables(" & CStr(i) & ").lng = " _
& Trim(str(.lng)) & vbCrLf & _
"Variables(" & CStr(i) & ").sng = " _
& Trim(str(.sng)) & vbCrLf & _
"Variables(" & CStr(i) & ").str = " & _
Chr(34) & Replace(.str, vbCrLf, ClRfRep) _
& Chr(34) & vbCrLf
Dim IsNum As Boolean
IsNum = True
For j = 1 To Len(.var)
If Not IsNumeric(Mid(.var, j, 1)) Then
IsNum = False: Exit For
End If
Next j
Select Case IsNum
Case True
SngVarStr = SngVarStr & _
"Variables(" & CStr(i) & ").var = " _
& Trim(str(.var)) & vbCrLf
Case False
SngVarStr = SngVarStr & _
"Variables(" & CStr(i) & ").var = " & _
Chr(34) & Replace(.var, vbCrLf, ClRfRep) _
& Chr(34) & vbCrLf
End Select
End With
Next i
GetSngVariables = Replace(SngVarStr, " ", " "): SngVarStr = ""
End Function
Private Sub UserForm_Activate()
ReDim Variables(0 To 10)
ClRfRep = Chr(34) & " & vbCrLf & _" & vbCrLf & Chr(34)
fullPath = Environ("userprofile") _
& "\Työpöytä\CtlSettings.Dat"
GetSavedSettings
Dim ChkArray As Variant
ChkArray = Me.IsCodeInserted()
If ChkArray(0) Then
SetSettings
Erase ChkArray
End Sub
Sub SaveControlSettings()
Settings(0).Setting = GetCtlPropValues(Me)
Settings(1).Setting = GetSngVariables()
For i = 0 To 1
If Settings(i).Setting <> "" Then
Settings(i).Setting = _
Left(Settings(i).Setting, _
Len(Settings(i).Setting) - 2)
End If
Next i
Open fullPath For Output As 1#
For i = LBound(Settings) To UBound(Settings)
Print #1, Settings(i).Setting
Next i: Close #1
End Sub
Sub GetSavedSettings()
Dim StrCode As String
If Dir(fullPath) = "" Then
Exit Sub
End If
Open fullPath For Input As #1
StrCode = Input$(LOF(1), 1)
Close #1
With ActiveWorkbook.VBProject. _
VBComponents(Me.Name).CodeModule
For i = ActiveWorkbook.VBProject. _
VBComponents(Me.Name).CodeModule.CountOfLines _
To 1 Step -1
If InStr(.Lines(i, 1), _
"Set CodeToExecute = Nothing") > 0 Then
.ReplaceLine i, StrCode
Exit For
End If
Next i
End With
StrCode = ""
End Sub
Private Sub UserForm_QueryClose( _
Cancel As Integer, CloseMode As Integer)
SaveControlSettings
Dim ChkArray As Variant
ChkArray = Me.IsCodeInserted()
If ChkArray(0) = True And ChkArray(1) > 0 Then
Dim StrCode As String
StrCode = _
"Sub SetSettings()" & vbCrLf & _
" Set CodeToExecute = Nothing" & vbCrLf & _
"End Sub"
With ActiveWorkbook.VBProject. _
VBComponents(Me.Name).CodeModule
For i = ActiveWorkbook.VBProject. _
VBComponents(Me.Name).CodeModule.CountOfLines _
To ChkArray(1) Step -1
.DeleteLines i
Next i
.InsertLines .CountOfLines + 1, StrCode
End With
End If
Erase ChkArray
End Sub
Function IsCodeInserted() As Variant
Dim CodeInserted As Boolean, spos As Long
Dim retArray(1) As Variant
For i = 1 To ActiveWorkbook.VBProject. _
VBComponents(Me.Name).CodeModule.CountOfLines
If InStr(ActiveWorkbook.VBProject. _
VBComponents(Me.Name).CodeModule.Lines(i, 1), _
"Sub SetSettings()") > 0 And _
InStr(ActiveWorkbook.VBProject. _
VBComponents(Me.Name).CodeModule.Lines( _
i + 1, 1), Me.Name) > 0 Then
CodeInserted = True: spos = i: Exit For
End If
Next i
retArray(0) = CodeInserted: retArray(1) = spos
IsCodeInserted = retArray(): Erase retArray
End Function
Sub SetSettings()
Set CodeToExecute = Nothing
End SubNea oot guru
Lisäksi on myös olemassa PropertyBag-objekti, johon voi tallentaa melkein mitä vain. Käytännössä...
1) Asetukset tallennettaessa käytetään WritePropertyä.
2) Avataan binääritiedosto ja tallennetaan PropertyBagin Content (se on Byte-taulukko).
3) Ladattaessa sijoitetaan uuteen PropertyBagiin ladattu Byte-taulukko käyttäen Contentia.
4) Luetaan asetukset takaisin paikalleen ReadPropertyllä. Jos jokin asetus puuttuu, niin tyydytään oletusasetukseen.
Tällä tavoin voi myös tallentaa mm. Picturet. Menetelmän haittapuoli on se, että jos koodin haluaa päivittää toiselle ohjelmointikielelle, niin tiedostoja ei voi enää kovin helposti lukea. Aika pitkälle tämmöinen VB6:n oma juttu.
Heippa taas!
PropertyBag luokka on oikeastaan melko yksinkertainen rakentaa ja voidaan toteuttaa helposti esim. VB.NET'llä...
Asettamalla assembly’n CLSCompliant attributti arvon true voidaan käännettyä .dll'a käyttää missä tahansa .NET'ä tukevassa ympäristössä...homma toimii myös esim. VBA-ympäristössä jos Assemblyn ComVisible attribuutti on asetettu arvoon true ja samainen atribuutti-arvo on asetettu myös luokan sisäisille proseduureille. Jutska vaatii tällöin myös tyyppien erillistä rekisteröintä.
PropertyBag-luokan sisällä olevaan Collection-objektiin pukaataan haluttu kama ja objekti castataan sitten Byte-taulukoksi ( = PropertyBag.Contents). ByteArray voidaankin sitten tallennella suoraan binaari-tiedostoksi...
Toiminta eroaa VBA-puolella hieman .NET-ympyröistä, elikäs VBA-puolta varten oli rakennettava luokan sisälle erillinen aliohjelma, jonka avulla tiedostosta luettu dataa voidaan pukata takaisin (.Net puolella Contents-Property toimii suoraan & moitteetta), elikäs extra-aliohjelman tarkoitus on pukata
tiedostosta luettu data luokan Collection objektiin, joka oli ensin asetettava julkiseksi ja varustettava ComVisible(True) attribuutilla, no tämä ei vielä aivan riittänyt vaan piti rakennella vielä erillinen luokka, jolla castata binaaritiedostosta Tavu-taulukkoon luettu data takaisin objektiksi, pukattavaksi edelleen takaisin PropertyBag'n Collection-objektiksi...
Koska luokka ei pysty serialisoimaan Sytem.__ComObject tyyppiä niin picturet jää VBA'ssa edelleenkin tallentelematta PropertyBag'n.
että tämmöistä hauskaa tällä kertaa…
Heippa taas!
rupes senverran jurppimaan toi System.__ComObject kastaus, että päätin viritellä kuvan tallennuksen mutkan kautta...
elikäs luo VB:llä uusi ClassLibrary projekti nimellä: MyPropertyBag ja uudelleennimeä Project Explorerissa NewClass.vb nimellä PropertyBag.vb tuplaklikkaa samaista kuvaketta & copy/pasteta alla oleva koodi kaiken sen päälle mitä on näkyvissä PropertyBag.vb'n koodi-ikkunassa...
VB.NET Projekti - MyBropertyBag (ClassLibrary)
PropertyBag.vb:
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Runtime.Serialization.Formatters.Binary
<ClassInterface(ClassInterfaceType.AutoDual)> _
<ComVisible(True)> _
<ProgId("MyBropertyBag.PropertyBag")> _
Public Class PropertyBag
Inherits MarshalByRefObject
<ComVisible(True)> _
Public objCon As New Collection
<ComVisible(True)> _
Public Sub WriteProperty(ByVal szobjDesc As String, _
ByVal objValue As Object)
objCon.Add(objValue, szobjDesc)
End Sub
<ComVisible(True)> _
Public Function ReadProperty(ByVal szobjDesc As String, _
Optional ByVal ObjDefValue As Object = Nothing) As Object
If objCon.Contains(szobjDesc) = True Then
Return objCon.Item(szobjDesc)
Else
Return ObjDefValue
End If
End Function
<ComVisible(True)> _
Public Property Contents() As Object
<ComVisible(True)> _
Get
Dim objMemStream As New MemoryStream
Dim objFormatter As New BinaryFormatter
objFormatter.Serialize(objMemStream, objCon)
Return objMemStream.ToArray()
End Get
<ComVisible(True)> _
Set(ByVal value As Object)
Dim objMemStream As MemoryStream
Dim objFormatter As New BinaryFormatter
objCon.Clear()
objMemStream = New MemoryStream(CType(value, Byte()))
objCon = objFormatter.Deserialize(objMemStream)
End Set
End Property
<ComVisible(True)> _
Public Sub SetContents(ByVal obj As Object)
objCon = obj
End Sub
<ComVisible(True)> _
Public Sub Clear()
objCon.Clear()
End Sub
End Classklikkaa Project Explorerissa References-kuvaketta hiiren oikealla, valitse Add Reference, valitse GAC-välilehti, etsi listalta Imports System.Runtime.Serialization, tuplaklikka nimeä ja painele OK:ta...valitse valikkoriviltä Project/Project Options...ruksaa valinta: Register for COM Interop...ruksaa Signing-välilehdeltä valinta: Sign the assembly, valitse laatikosta valinta: Create
ja klikkaa OK:ta...tarkista vielä Application-välilehdeltä, että Output type on ClassLibrary...tallenna koko projekti...Tuplaklikkaa Projekt Explorerissa AssemblyInfo.vb kuvaketta ja copy/pasteta alla oleva koodi kaiken AssemblyInfo.vb koodi-ikkunassa näkyvän päälle...
AssemblyInfo.vb:
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly: AssemblyTitle("MyBropertyBag")>
<assembly: AssemblyDescription("")>
<assembly: AssemblyConfiguration("")>
<assembly: AssemblyCompany("")>
<assembly: AssemblyProduct("MyBropertyBag")>
<assembly: AssemblyCopyright("")>
<assembly: AssemblyTrademark("")>
<assembly: AssemblyCulture("")>
<assembly: ComVisible(True)>
<assembly: CLSCompliant(True)>
' vaihda GUID luomalla oma GUID GuidGen apu-ohjelmalla (Registry Format)
' kopioi leikepöydälle, leikepöydältä hipsujen väliin & poista aaltosulkeet
<Assembly: Guid("D594DCBB-216E-4f4e-BD7B-83548B9EFEB3")>
<Assembly: AssemblyVersion("1.0.0.0")>
<Assembly: AssemblyFileVersion("1.0.0.0")>Tallenna ja käännä projekti...avaa Resurssienhallinta, siirry projektisi ...\Bin\Debug hakemistoon & kopioi MyPropertyBag.dll Windows\System32 -hakemistoon...avaa komentokehote-ikkuna
kirjoita: CD \Windows\System32 & painele Enter-näpykkää...
kirjoita: TlbExp MyPropertyBag.dll /out: MyPropertyBag.Tlb & painele...
kirjoita: gacgutil /i MyPropertyBag.dll &...
kirjoita: ngen install MyPropertyBag.dll &...
kirjoita: regasm MyPropertyBag.dll /tlb: MyPropertyBag.tlb &...
luo toinen VB.NET ClassLibrary projekti nimellä: ConvertObject &
toista edellisen kaavan mukaiset toiminnot (uudelleen nimeä NewClass.vb -> CastClass.vb ja rekisteröi ConvertObject.dll / ConvertObject.tlb nimillä)
VB.NET Projekti - ConvertObject (ClassLibrary)
CastClass.vb:
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Windows.Forms
<ClassInterface(ClassInterfaceType.AutoDual)> _
<ComVisible(True)> _
<ProgId("ConvertObject.CastClass")> _
Public Class CastClass: Inherits MarshalByRefObject
<ComVisible(True)> _
Public Function ObjectToByteArray(ByVal _Object As Object) As Byte()
Dim exerr As Boolean = False
Dim _ByteArray() As Byte = Nothing
Dim bf As BinaryFormatter = New BinaryFormatter()
Dim ms As MemoryStream = New MemoryStream()
Select Case _Object.GetType().ToString
Case "System.__ComObject"
Try
_ByteArray = CType(_Object, Byte())
Catch _ExceptionCom As Exception
MsgBox(_ExceptionCom.Message.ToString)
End Try
Case Else
Try
bf.Serialize(ms, _Object)
_ByteArray = ms.ToArray()
Catch _Exception As Exception
MsgBox(_Exception.Message.ToString)
End Try
End Select
Return _ByteArray
End Function
<ComVisible(True)> _
Public Function ByteArrayToObject(ByVal obj As Object) As Object
Dim _ByteArray() As Byte = obj
Dim bform As BinaryFormatter = New BinaryFormatter()
Dim mstream As MemoryStream = New MemoryStream()
Dim _Object As Object = Nothing
Try
mstream.Write(_ByteArray, 0, _ByteArray.Length)
mstream.Seek(0, SeekOrigin.Begin)
_Object = bform.Deserialize(mstream)
Catch ex As Exception
MsgBox(ex.Message.ToString)
End Try
Return _Object
End Function
End ClassAssemblyInfo.vb:
Imports System.Reflection
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
<assembly: AssemblyTitle("ConvertTo")>
<assembly: AssemblyDescription("")>
<assembly: AssemblyConfiguration("")>
<assembly: AssemblyCompany("")>
<assembly: AssemblyProduct("ConvertTo")>
<assembly: AssemblyCopyright("Copyright 2009")>
<assembly: AssemblyTrademark("")>
<assembly: AssemblyCulture("")>
<assembly: ComVisible(True)>
<assembly: CLSCompliant(True)>
' vaihda GUID luomalla oma GUID GuidGen apu-ohjelmalla (Registry Format)
' kopioi leikepöydälle, leikepöydältä hipsujen väliin & poista aaltosulkeet
<assembly: Guid("6B3DA679-D293-4f38-BF91-9DD7ED332B49")>
<assembly: AssemblyVersion("1.0.0.0")>
<Assembly: AssemblyFileVersion("1.0.0.0")>VBA Projekti - MyPropertyBag.xls (testi)
ThisWorkbook:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Saved = True
End Sub
Private Sub Workbook_Open()
Application.WindowState = xlMinimized
If Not UserForm1.Visible Then
UserForm1.Show
End If
End SubUserForm1:
' VBA Projektiin referenssit:
'
' MyPropertyBag
' (C:\WINDOWS\System32\MyPropertyBag.tlb)
'
' ConvertObject
' (C:\WINDOWS\System32\ConvertObject.tlb)
' Neobase OLE interfaces & functions v8.1
' (C:\WINDOWS\System32\olelib.tlb)
' imppaa olelib.zip [linkki "http://www.elisanet.fi/nea.fi/downloads/olelib.zip"]täältä[/linkki] & pura ..\WINDOWS\System32-hakemistoon
' UserForm1:
' formille pari Image-controllia & pari nappia
Private propBag As MyBropertyBag.PropertyBag
Private conVert As ConvertObject.CastClass
Private FullPath As String
Private Sub UserForm_Activate()
Dim BasePath As String
Dim FileName As String
Dim picBasePath As String
Dim picFileName As String
Dim picFullPath As String
BasePath = Environ("userprofile") & "\Työpöytä"
FileName = "arrayData.dat"
FullPath = BasePath & "\" & FileName
picBasePath = Environ("userprofile") & _
"\Omat tiedostot\Omat kuvatiedostot"
picFileName = "picture1.bmp"
picFullPath = picBasePath & _
"\" & picFileName
Me.Image1.Picture = LoadPicture(picFullPath)
End Sub
Private Sub CommandButton1_Click()
WriteTo Me
End Sub
Private Sub CommandButton2_Click()
ReadFrom
End Sub
Private Sub WriteTo(frm As Variant)
Dim i As Integer
Dim ctl As Control
Set ctl = frm.Image1
Dim propBag As PropertyBag
Set propBag = New PropertyBag
If Not Image1.Picture Is Nothing Then
If ArrayExists(ImageData()) Then Erase ImageData()
FromImageControlToByteArray Image1.Picture
propBag.WriteProperty "Image1", ImageData()
End If
If Dir(FullPath) <> "" Then
Kill (FullPath)
Do While Dir(FullPath) <> "": Loop
End If
Dim Bytes() As Byte
Bytes = propBag.Contents
Open FullPath For Binary As #1
Put 1, , Bytes: Close #1
propBag.Clear
End Sub
Private Sub ReadFrom()
If Dir(FullPath) <> "" Then
On Error Resume Next
Set propBag = New PropertyBag
If Err <> 0 Then
Err.Clear
End If
On Error GoTo 0
Dim Bytes() As Byte
Dim strBytes As String
Open FullPath For Binary Access Read As #1
strBytes = Space(LOF(1))
Get 1, , strBytes: Close #1
Bytes = StrConv(strBytes, vbFromUnicode)
Do While UBound(Bytes()) = 0: Loop
Set conVert = New ConvertObject.CastClass
Dim obj As Object
Set obj = conVert.ByteArrayToObject(Bytes)
propBag.SetContents obj
Set conVert = Nothing
If ArrayExists(ImageData()) Then Erase ImageData()
ImageData() = propBag.ReadProperty("Image1")
Set Image2.Picture = _
ArrayToPicture(ImageData(), 1, UBound(ImageData))
End If
End Sub
Private Sub UserForm_QueryClose(Cancel As _
Integer, CloseMode As Integer)
Application.Quit
End SubModule1:
Global ImageData() As Byte
Private Declare Function CreateStreamOnHGlobal _
Lib "ole32" (ByVal hGlobal As Long, ByVal _
fDeleteOnRelease As Long, ppstm As Any) As Long
Private Declare Function GlobalAlloc Lib "kernel32" _
(ByVal uFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GetHGlobalFromStream Lib "ole32" _
(ByVal pstm As IStream, phglobal As Long) As Long
Private Declare Sub MoveMemory Lib "kernel32" Alias _
"RtlMoveMemory" (Dest As Any, src As Any, ByVal cb As Long)
Private Declare Function GlobalSize Lib "kernel32" _
(ByVal hMem As Long) As Long
Private Declare Function GlobalLock Lib _
"kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib _
"kernel32" (ByVal hMem As Long) As Long
Private Declare Function OleLoadPicture Lib "olepro32" _
(pStream As Any, ByVal lSize As Long, ByVal _
fRunmode As Long, riid As Any, ppvObj As Any) As Long
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias _
"RtlMoveMemory" (ByRef Destination As Any, _
ByRef Source As Any, ByVal Length As Long)
Private Const PictureID = &H746C&
Private Const S_OK = 0
Private Type PictureHeader
Magic As Long
Size As Long
End Type
Public Function ArrayToPicture(inArray() As Byte, _
Offset As Long, Size As Long) As IPicture
Dim o_hMem As Long
Dim o_lpMem As Long
Dim aGUID(0 To 3) As Long
Dim IIStream As IUnknown
aGUID(0) = &H7BF80980
aGUID(1) = &H101ABF32
aGUID(2) = &HAA00BB8B
aGUID(3) = &HAB0C3000
On Error GoTo FuncErrorHandler
o_hMem = GlobalAlloc(&H2&, Size)
If Not o_hMem = 0& Then
o_lpMem = GlobalLock(o_hMem)
If Not o_lpMem = 0& Then
CopyMemory ByVal o_lpMem, inArray(Offset), Size
Call GlobalUnlock(o_hMem)
If CreateStreamOnHGlobal(o_hMem, 1&, IIStream) = 0& Then
Call OleLoadPicture(ByVal ObjPtr(IIStream), 0&, _
0&, aGUID(0), ArrayToPicture)
End If
End If
End If
Exit Function
FuncErrorHandler:
Err.Clear
End Function
Public Sub FromImageControlToByteArray( _
ByVal oObj As StdPicture)
Dim oIPS As IPersistStream
Dim oStream As IStream, hGlobal As Long, lPtr As Long
Dim lSize As Long, Hdr As PictureHeader
Dim lRes As Long
Set oIPS = oObj
lRes = CreateStreamOnHGlobal(0, True, oStream)
If lRes = S_OK Then
oIPS.Save oStream, True
If GetHGlobalFromStream(oStream, hGlobal) = S_OK Then
lSize = GlobalSize(hGlobal)
lPtr = GlobalLock(hGlobal)
If lPtr Then
lSize = lSize - Len(Hdr)
ReDim ImageData(1 To lSize)
MoveMemory ImageData(1), ByVal lPtr + Len(Hdr), lSize
End If
GlobalUnlock hGlobal
End If
Set oStream = Nothing
End If
End Sub
Public Function ArrayExists(Bytes() As Byte) As Boolean
Dim lb As Long
On Error Resume Next
lb = LBound(Bytes())
If Err <> 0 Then
Err.Clear: On Error GoTo 0
ArrayExists = False: Exit Function
End If
ArrayExists = True
End FunctionAihe on jo aika vanha, joten et voi enää vastata siihen.