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 Sub
Nea 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 Class
klikkaa 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 Class
AssemblyInfo.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 Sub
UserForm1:
' 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 Sub
Module1:
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 Function
Aihe on jo aika vanha, joten et voi enää vastata siihen.