Welcome to Weblog @ rebex.cz Sign in | Help

Jak nastavit čas ve Windows CE z VB.NET

Václav Bárta ve čtvrtek při programování pro .NET Compact Framework (což je .NET Framework pro PocketPC a jiná zařízení s Windows CE) narazil na velmi nepříjemný rozdíl mezi C# a VB.NET. Konkrétně se jedná o neschopnost VB.NET volat funkce importované z unmanaged dynamické knihovny, pokud jsou jejich parametry ukazatelé a my přikážeme Basicu místo nich předávat struktury - VB.NET to umí. Jenže v Compact Framework to prostě nefunguje a výsledkem je pád se výjimkou NotSupportedException. Velká části Windows API je proto nepřístupná, mimo jiné i funkce SetSystemTime z coredll.dll. Z C# se postižené funkce nejspíš díky ukazatelům a možnosti označit kód jako unsafe dají volat bez problémů.

Přestože VB.NET nemám rád (hlavně z iracionálních důvodů), odmítl jsem se smířit s nemožností nastavit z tohoto jazyka systémový čas. Půjde to i bez ukazatelů! Součástí namespacu System.Runtime.InteropServices je přece třída Marshal a ta poskytuje metodu StructureToPtr, která dokáže zkopírovat obsah instance objektu do bloku paměti alokovaného třeba z heapu (český výraz hromada mi nikdy nepřirostl k srdci) a odkazovaného typem IntPtr, a dokonce nechybí ani v .NET CF! Kdyby v tom nebyl jeden drobný háček - v .NET CF chybí ve třídě Marshal metody na alokování paměti - řešení by bylo na světě. Ale budiž. Když neumí pamět alokovat Marshal, můžeme použít funkce API LocalAlloc a LocalFree (ano, ty se dají úspěšně volat z VB.NET - žádný jejich parametr není ukazatel na strukturu). Zkusil jsem to tedy takto.

A výsledek? Funguje to! Pomocí metody TimeCf.SetSystemTime se dá nastavit systémový čas na PocketPC i z VB.NET. Toto řešení je vhodné i pro C#, protože odpadá nutnost označit kód jako unsafe.

Import System
Import System.Runtime.InteropServices

Public Class TimeCf
    Private Class SystemTime
        Public Year As Short
        Public Month As Short
        Public DayOfWeek As Short
        Public Day As Short
        Public Hour As Short
        Public Minute As Short
        Public Second As Short
        Public MilliSecond As Short
    End Class

    Private Declare Function SetSystemTime Lib "coredll.dll" _
        (ByVal st As IntPtr) As Integer

    Private Declare Function GetLastError Lib "coredll.dll" _
        () As Integer

    Private Declare Function LocalAlloc Lib "coredll.dll" _
        (ByVal Flags As Integer, ByVal Bytes As Integer) As IntPtr

    Private Declare Function LocalFree Lib "coredll.dll" _
        (ByVal Ptr As IntPtr) As IntPtr

    Public Shared Sub SetSystemTime(ByVal dt As DateTime)
        Dim systime As New SystemTime
        systime.Year = dt.Year
        systime.Month = dt.Month
        systime.DayOfWeek = 0
        systime.Day = dt.Day
        systime.Hour = dt.Hour
        systime.Minute = dt.Minute
        systime.Second = dt.Second
        systime.MilliSecond = dt.Millisecond

        Dim bytes As Integer = Marshal.SizeOf(systime)
        Dim ptr As IntPtr = LocalAlloc(0, bytes)
        Try
            Marshal.StructureToPtr(systime, ptr, False)
            If SetSystemTime(ptr) = 0 Then
                Dim e As Integer = GetLastError()
                Dim m As String
                m = String.Format("Cannot set system time (error {0}).", e)
                Throw New Exception(m)
            End If
        Finally
            LocalFree(ptr)
        End Try
    End Sub

End Class
Published 13. října 2003 17:42 by lukasp

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: Jak nastavit čas ve Windows CE z VB.NET

Možná Vás inspiruje i varianta klasické funkce VarPtr pro VB.NET, používající metodu AddrOfPinnedObject GarbageCollectoru


Public Function VarPtr(ByVal o As Object) As Integer

Dim GC As System.Runtime.InteropServices.GCHandle = System.Runtime.InteropServices.GCHandle.Alloc(o, System.Runtime.InteropServices.GCHandleType.Pinned)

Dim ret As Integer = GC.AddrOfPinnedObject.ToInt32

GC.Free()

Return ret

End Function
20. října 2004 18:37 by lukasp

# re: Jak nastavit čas ve Windows CE z VB.NET

Díky za příspěvek, je to zdá se ideální řešení, nepotřebuje LocalAlloc ani LocalFree.
20. října 2004 18:45 by lukasp

# re: Jak nastavit čas ve Windows CE z VB.NET

interesting

13. června 2007 4:50 by Angelos

# re: Jak nastavit čas ve Windows CE z VB.NET

Interesting...

14. června 2007 20:42 by Aleksiu

# re: Jak nastavit čas ve Windows CE z VB.NET

interesting

16. června 2007 16:35 by Kyriakos

# re: Jak nastavit čas ve Windows CE z VB.NET

Interesting...

10. července 2007 5:33 by Dionyssios

# re: Jak nastavit čas ve Windows CE z VB.NET

Interesting...

10. července 2007 6:56 by Nikolaos

# re: Jak nastavit čas ve Windows CE z VB.NET

Interesting...

10. července 2007 16:03 by Nico

# re: Jak nastavit čas ve Windows CE z VB.NET

interesting

11. července 2007 5:16 by Prokopios

# re: Jak nastavit čas ve Windows CE z VB.NET

Interesting...

4. srpna 2007 6:25 by Ari

# thomson@physics.otago.ac.nz

12. prosince 2007 21:17 by Walker

# for test my car

this topic for test cars

19. července 2008 19:11 by exculkmex

Leave a Comment

(required) 
required 
(required)