VBA Tools

Archiwum z Luty, 2012

Lista folderów Outlooka

napisane przez Oskar w dniu wtorek, 21 Luty, 2012, w kategorii Porady - Outlook

Poniżej znajduje się kod, który zwraca w oknie immediate [Ctrl+G] nazwy folderów. Ciekawą w jej konstrukcji jest zapętlenie wywołania funkcji, która sama wywołuje „siebie”, aby pobrać dane folderu podrzędnego.

W czym kod ten może być przydatny? Otóż do tworzenia archiwizacji czy eksportu danych do baz danych z zachowaniem pełnej struktury zapisu.

Sub OutlookFolders()
 Dim olNamespace As Outlook.NameSpace
 Dim olFolder As Outlook.Folders
 Dim objFolder As Outlook.MAPIFolder

 Set olNamespace = Application.GetNamespace("MAPI")
 Set olFolder = olNamespace.Folders

 For Each objFolder In olFolder
   Call LoopFolders(objFolder.Folders)
 Next

 Set olNamespace = Nothing
 Set olFolder = Nothing
End Sub

Private Sub LoopFolders(Folders As Outlook.Folders)
 Dim Fold As Outlook.MAPIFolder

 For Each Fold In Folders
   Debug.Print Fold.FolderPath
   DoEvents
   If Fold.Folders.Count Then _
     LoopFolders Fold.Folders 
 Next
End Sub

Rys 1. Lista folderów.

 

Aby pobrać jedynie nazwę bez ścieżki należy zamiast FolderPath pobrać parametr Name lub w obecnym wymiarze pobrać funkcją InStrRev miejsce znaku „\”

 

(c) Shon Oskar – www.VBATools.pl

Wszelkie prawa zastrzeżone. Żadna część ani całość tego artykułu nie może być powielana ani publikowana bez zgody autora.

Skomentuj przejdź do artykułu ...

VBS Wywołanie polecenia w tle

napisane przez Oskar w dniu poniedziałek, 20 Luty, 2012, w kategorii Porady - Excel

Zastanawiacie się jak można wykonać modyfikację pliku, tak aby użytkownik się nie zorientował? Jest wiele metod, począwszy od napisania dodatku który uruchomimy wraz z komputerem lub z autostartem Excela, można podmienić plik po GPO (komputer w domenie) lub uruchomić plik polecenia skryptowego.

Ta porada będzie właśnie poświęcona wykorzystaniem języka skryptowego do modyfikacji istniejącego pliku Excela.

Poniżej znajdziemy treść pliku tekstowego z rozszerzeniem vbs, który z łatwością po odpaleniu zrozumie nasz procesor działający w systemie Windows.

'MVP OShon from VBATools.pl
Dim XLApp 'As Object 'Excel.Application
Dim wkb 'As Object
Dim wks 'As Object
Dim sciezka 'As String
sciezka = "c:\temp\test.xlsx"
Set XLApp = CreateObject("Excel.Application")
 XLApp.Visible = False
 XLApp.Workbooks.Open sciezka
 Set wkb = XLApp.ActiveWorkbook
 Set wks = wkb.Sheets(1)
 wks.Cells(1,1) = "Hello Word"
 wkb.Close True
 XLApp.Quit
 Set wkb = Nothing
 Set wks = Nothing
 Set XLApp = Nothing

Co on właściwie robi?

Otwiera aplikacje Excel w trybie ukrytym, następnie odwołuje się do pierwszego arkusza i modyfikuje komórkę A1 wstawiając tam stringa. Po zakończeniu operacji wyłącza aplikację i czyści pamięć. Można zauważyć że w języku skryptowym nie odwołujemy się określając zmienne – pozostawiamy to procesorowi. Niestety taka forma nie jest mile widziana ani w VB ani VBA, gdzie prędkość działania jest uzależniona od prawidłowej deklaracji.

 

Aby uruchomić plik *.vbs należy go zapisać i albo umieścić stosowną komendę ze ścieżką jego przetrzymywania w rejestrze użytkownika:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce

„C:\jakis_katalog\plik.vbs” /nosplash /minimized

albo umieścić plik lub jego link w autostarcie (zwracając uwagę na późniejszą dezintegracje pliku, aby proces ten nie powtarzał się za każdym razem podczas uruchomienia komputera).

 

Import danych oraz aktywacja przypomnień dla terminów po imporcie z MS Excel

napisane przez Oskar w dniu poniedziałek, 21 Czerwiec, 2010, w kategorii Porady – Excel, Porady – Outlook

MS Outlook pozwala zaimportować większą ilość terminów do kalendarza dzięki utworzonej wcześniej bazie danych w programie Excel.

Aby przystąpić do pracy należy wyselekcjonować dane, jakie będą istotne do utworzenia obiektu kalendarzowego. Poniższy rysunek pokazuje przykładową bazę elementów (arkusz: Dane), jakie wykorzystamy przy imporcie do Outlooka.

Rys 1. Przykładowa baza danych do importu jako obiekty kalendarza

Poniżej przykład uporządkowanego obszaru bazy, np. wielkości tablicy „A:J” (od Temat do Opis). Pola nazw kolumn zgodne z importem rozumianym przez Outlooka to:

Temat, Datarozpoczęcia, Czasrozpoczęcia, Datazakończenia, Czaszakończenia, Przypomnienie wł/wył, Dataprzypomnienia, Czasprzypomnienia, Kategorie, Opis

Rys 2. Przygotowanie linii – odpowiedniki nowych obiektów

Warunkiem koniecznym do prawidłowego importu jest nadanie obszaru roboczego o nazwie Kalendarz (arkusz: Outlook).

W przypadku, kiedy nasza baza zwiększa swoją objętość, aktualizacje obszaru możemy realizować za pomocą poniższej instrukcji umieszczonej w module Excela:

Dim oName As Name

For Each oName In ActiveWorkbook.Names
If oName.Name = „Kalendarz” Then oName.Delete
Next
ActiveWorkbook.Names.Add Name:=”Kalendarz”, _
RefersTo:=Range(„A1:J” & Cells(Rows.Count, „A”).End(xlUp).Row)

Jeśli już posiadamy jasno określoną matrycę, przystępujemy do importu danych w Outlooku. Przedtem należy wyjść z pliku bazy danych (zamknąć plik Excela). Mechanizm importu możemy znaleźć w Outlooku: Menu/Plik/Importuj lub eksportuj/Import z innego programu lub pliku/Microsoft Excel.

Wybieramy plik oraz stosowną opcję metody importu.

Wskazujemy folder kalendarza (może to być dowolny folder, inny niż domyślny, o właściwościach kalendarza).

Możemy określić inne pola importu, jednakże powyższy przykład bazy zawiera większość stosowanych.

Niestety import ten posiada jedną wadę. Pozbawiony jest prawidłowego odczytu pola: Przypomnienie wł/wył = PRAWDA, pomimo prawidłowego wskazania. W przypadku umieszczenia anglojęzycznej nazwy parametru pola otrzymujemy identyczny skutek.

Powyższy rysunek nie zawiera zaznaczonego przypomnienia, choć w chwili importu data przypomnienia była wcześniejsza niż data importu danych.

Istnieje ręczna metoda, polegająca na ustawieniu widoku kalendarza: Widok/Widok bieżący/Wszystkie terminy lub Widok/Rozmieść wg/Kategorie i przy wyciągnięciu nowej kolumny Przypomnienie, jest możliwość naciśnięcia w jego puste pole (pojawi się dzwoneczek) oznaczający jego nadanie w dacie i godzinie terminu.

Wyciągnięcie kolumny realizujemy poprzez prawy klik na pasku nazw kolumn/Wybór pola/Przenosimy przytrzymując myszą nazwę kolumny Przypomnienie i puszczając przycisk w odpowiednim miejscu.

Napotykamy na problemem, gdy ilość kliknięć jest równa np. 100 lub więcej. Praca taka wydaje się zbyt mozolna, zwłaszcza mając na uwadze cykliczność naszych działań.

Aby temu zaradzić i proces ten zautomatyzować, należy użyć poniżej napisanej procedury, która zbada czy przypomnienie terminów zaimportowanych do Outlooka jest aktualne w dacie. Wszystkie takie obiekty uaktualni, dodając „dzwoneczek” (włączy dla tych obiektów przypomnienie). Uniwersalność procedury pozwala umieścić ją zarówno w module Outlooka, jak i Excela (w Excelu należy w Referencjach dodać bibliotekę Oulooka Menu/Tools/References -> Microsoft Outlook …Object libary).

Option Explicit
Sub wlaczanie_przypomninia()
'MVP OShon from VBATools.pl
Dim msg$, Response$, q&

msg = "Procedura włączenia przypomnień do terminów w kalendarzu Outlooka" & vbCr & vbCr _
& "Aby kontynuować naciśnij ''Tak''" & vbCr _
& "Aby anulować operacje naciśnij ''Nie''"
On Error GoTo blad
Response = MsgBox(msg, vbYesNo + vbExclamation + vbDefaultButton2, " Aktualizacja dzwoneczków")
If Response = vbYes Then
  Dim OutApp As Object
    Set OutApp = CreateObject("Outlook.Application")
  OutApp.Session.Logon
  Dim oApptFolder As MAPIFolder
    Set oApptFolder = OutApp.Application.GetNamespace("MAPI").GetDefaultFolder(olFolderCalendar)
Dim oCalendar As AppointmentItem
Dim olApp As Items
  Set olApp = oApptFolder.Items
  For q = 1 To olApp.Count
    DoEvents
    Set oCalendar = olApp.Item(q)
    If Not oCalendar.Categories = "" _
      And oCalendar.ReminderSet = False _
      And oCalendar.Start >= Now Then
      'Jeśli nie określimy nazwy dla kategorii należy zmienić pow. warunek.
      oCalendar.ReminderSet = True
      oCalendar.Save
    End If
  Set oCalendar = Nothing
Next q
MsgBox "Dzwoneczki uaktywnione!", vbInformation, "O'Shon machine from VBATools."
Set OutApp = Nothing
Set oApptFolder = Nothing
End If
Exit Sub

blad:
MsgBox "Błąd: " & Err.Number & vbCr & Err.Description, vbExclamation
End Sub

Jeśli automat zainteresuje się naszymi terminami, dla których przypomnienie miało nastąpić o wiele wcześniej, niż data wydarzenia kalendarzowego, należy anulować potwierdzenie przypomnienia naciskając: Odrzuć wszystkie.

W kalendarzu Outlooka pozostaną tylko te, co do których termin przypomnienia będzie skutkował komunikatem w nadanym, aktualnym terminie.

Skomentuj przejdź do artykułu ...

Jak działa Progressbar

napisane przez Oskar w dniu niedziela, 19 Luty, 2012, w kategorii Porady - Excel

Ten prosty przykład uzmysłowi wam jak działa pasek postępu. Elementarnym czynnikiem jest określenie wartości maksymalnej dla paska. W czasie przekazywania kolejnych parametrów, wartość paska będzie „dochodzić” do tej wartości.

Poniżej można znaleźć kod, który otwiera w zadeklarowanym katalogu pliki jakie spełniają określony warunek. Użyta w kodzie metoda FSO pozwala na przekazanie nazwy kolejnego pliku w pętli. Pliki są otwierane i zamykane bez zapisu. Parametr .value jest przekazywany.

Oto prosty przykład jak działa pasek postępu.

rys 1. Pasek postępu przypisany do otwieranych kolejno plików.

 

Option Explicit
Private Sub UserForm_Initialize()
'Taki sposób nie jest dobry ponieważ kod zacznie działać zanim forma się wyświetli
'Call test_4progres
End Sub

Private Sub CommandButton1_Click()
'to jest dobry sposób - wymuszenie przyciskiem
Call test_4progres
End Sub

Private Sub UserForm_Activate()
'to jest dobry sposób - zadziała zaraz po wywołaniu formy
Call test_4progres
End Sub

Sub test_4progres()
'MVP OShon from VBATools.pl
Const sciezka$ = "C:\Temp\"
Dim ob As Object, pliki As Object, plik As Object
Dim folder As Object, r&

Set ob = CreateObject("Scripting.FilesystemObject")
Set folder = ob.GetFolder(sciezka)
Set pliki = ob.GetFolder(folder).Files

ProgressBar1.Value = 0 'zerujemy pasek
ProgressBar1.Max = 9   'określamy maximum postępu 

With Application
 .ScreenUpdating = False
 .EnableEvents = False
 .Calculation = xlCalculationManual
 .DisplayAlerts = False
 For Each plik In pliki
  DoEvents 'kluczowy parametr dzięki któremu będziemy widzieć postęp paska
  If Mid(LCase(plik), InStrRev(plik, ".") + 1, 3) = "xls" Then
    Workbooks.Open Filename:=(sciezka & plik.Name) 'otwieramy tylko pliki XLS
    ProgressBar1.Value = r 'przekazujemy kolejny parametr
    r = r + 1
    ActiveWorkbook.Close False
    If r = 10 Then GoTo przerwij
  End If
 Next plik
przerwij:
 .ScreenUpdating = True
 .Calculation = xlCalculationAutomatic
 .EnableEvents = True
End With

Set ob = Nothing
Set folder = Nothing
Set pliki = Nothing
End Sub

 

Taką metodę można zastosować w Excelu, Outlooku, jak i w innych aplikacjach pakietu Office.

 

(c) Shon Oskar – www.VBATools.pl

Wszelkie prawa zastrzeżone. Żadna część ani całość tego artykułu nie może być powielana ani publikowana bez zgody autora.

Skomentuj przejdź do artykułu ...

Kopiowanie przyrostowe danych z innych skoroszytów

napisane przez Oskar w dniu czwartek, 16 Luty, 2012, w kategorii Porady - Excel

Kopiowanie przyrostowe często wpędza w zakłopotanie. Jak wykonać działanie szybko i bez konieczności szukania, zaznaczania zakresów, przechodzenia pomiędzy skoroszytami etc.

Poniżej przedstawiam drobny kod, który pokazuje jak otworzyć plik, zadeklarować obszar, odnaleźć w docelowym arkuszu ostatnią wypełnioną komórkę i do następnej import danych z zakresu pliku źródłowego. Zakładamy w nim iż plik źródłowy ma jeden lub pierwszy arkusz z danymi jakie nas interesują. Drugim założeniem jest iż kopiujemy wszystkie dane z zakresu kolumny A (może być zakres wielu kolumn).

Sub open_copy_paste_n_close()
'MVP OShon from VBATools.pl
Const nazwapliku$ = "c:\Temp\1.xlsx" 'Nazwa pliku do otwarcia
Dim thiswkb As Workbook, wkb As Workbook, min_row&
Set thiswkb = ActiveWorkbook
Call BlockEvScreenCalc(False, "Import danych...")
 Workbooks.Open Filename:=nazwapliku
Set wkb = ActiveWorkbook

Dim rng1 As Range, rng2 As Range
With wkb.Sheets(1)
 Set rng1 = .Range("a1:a" & .Cells(Rows.Count, "a").End(xlUp).Row)
End With
With thiswkb.Sheets("Arkusz1") 'arkusz docelowy
 min_row = .Cells(Rows.Count, "a").End(xlUp).Row
 If Len(.Range("a1")) > 0 Then min_row = min_row + 1 'jeśli mamy nagłówek
 Set rng2 = .Range("a" & min_row)
End With
rng1.Copy rng2
koniec:
On Error Resume Next
wkb.Close False
Set rng1 = Nothing
Set rng2 = Nothing
Set thiswkb = Nothing
Set wkb = Nothing
Call BlockEvScreenCalc(True) 
Exit Sub
blad:
Call BlockEvScreenCalc(True)
 MsgBox "Error: " & Err.Number & vbCr & Err.Description, vbCritical, "VBATools.pl"
Resume koniec
End Sub

Public Sub BlockEvScreenCalc(Optional ByVal bWlacz As Boolean, Optional Status As String)
 On Error Resume Next
 With Application
 If bWlacz Then
 .EnableEvents = True
 .Calculation = xlCalculationAutomatic
 .StatusBar = ""
 .ScreenUpdating = True
 .Cursor = xlDefault
 Else
 .ScreenUpdating = False
 .Calculation = xlCalculationManual
 .EnableEvents = False
 .StatusBar = Status
 .Cursor = xlWait
 End If
 End With
End Sub

(c) Shon Oskar – www.VBATools.pl

Wszelkie prawa zastrzeżone. Żadna część ani całość tego artykułu nie może być powielana ani publikowana bez zgody autora.

Skomentuj przejdź do artykułu ...

Windows 8 nadchodzi.

napisane przez Oskar w dniu czwartek, 16 Luty, 2012, w kategorii Informacje

Już jakiś czas temu, miałem dostęp do Windows 8  Developer preview. Jest to wersja dla programistów wydana dla jednostki przygotowanej do pracy w x64.

Wpierw instalacja jej na notebooku nie powiodła się, ponieważ domyślnie wsparcie dla procesora nie było włączone, jednakże później już bez problemów dała się okiełznać na VirtualBox.

Następną niespodzianką okazała się konieczność posiadania konta na WindowsLive. To on będzie kontrolował co używamy i kiedy instalujemy. On też od niedawna zintegrowany jest ze Skype, Outlook comunity addin, a dalej Facebook, Twiter i inne. Integracja z „social” nieunikniona. (czytaj dalej …)

Skomentuj :, przejdź do artykułu ...

Przeniesienie wiadomości do kosza folderu IMAP z Elementy wysłane

napisane przez Oskar w dniu środa, 15 Luty, 2012, w kategorii Porady - Outlook

Tematem tej porady jest potrzeba przeniesienia wiadomości po jej usunięciu z folderu elementy wysłane do folderu skrzynki, z której został on wysłany. Konta IMAP można skonfigurować tak, aby wskazać kierunek poczty przychodzącej oraz utworzyć regułę na skopiowanie wiadomości w obrębie struktury dostępnych folderów. Niestety usunięcie z przeniesieniem nie jest możliwe.

Proces ten nie jest skomplikowany ale wymaga utworzenia programu w VBA. Zaprogramowanie go, będzie opierało się na odrębnej procedurze. Powodem jest fakt iż Outlook nie posiada procedury zdarzeniowej, która by wywoływała czynność po usunięciu obiektu.

Rys 1. Opis schematu postępowania w strukturze folderów IMAP (przesłany przez Capacitor).

Poniżej umieszczone makro ma na zadanie przenieść wskazany lub otwarty mail, jednakże wywołanie tej procedury musi być podłączone do odrębnego przycisku. Dzięki mechanizmowi „Dostosowanie wstążki” dostępnego w opcjach Outlooka, jest możliwość dodania przycisku z podpiętym makrem. Samo podpięcie realizuje się po przez wybrania polecenia z grupy „Makra” a następnie w sekcji”Dostosuj wstążkę” utworzyć nową grupę i dopiero do niej dodać kod. Dodatkowo możemy zmienić nazwę wyświetlaną i dodać obrazek ikony.

Rys 2. Utworzenie skrótu do procedury VBA

Rys 3. Dostosowanie widoku

Sub Przenies_do_kosza_konta_imap()
'MVP OShon from VBATools.pl
Dim oMail  As MailItem, oFolder As MAPIFolder
On Error GoTo blad
Select Case TypeName(Application.ActiveWindow)
Case "Explorer":  Set oMail = ActiveExplorer.Selection.Item(1)
Case "Inspector": Set oMail = ActiveInspector.CurrentItem
Case Else: Exit Sub
End Select
 Dim konto As String: konto = oMail.SendUsingAccount
 Set oFolder = Application.GetNamespace("MAPI").Folders(konto).Folders("Deleted Items")
 oMail.Move oFolder
koniec:
 If Not oFolder Is Nothing Then Set oFolder = Nothing
 If Not oMail Is Nothing Then Set oMail = Nothing
Exit Sub
blad:
MsgBox Err.Number & " " & Err.Description, vbExclamation, "VBATools.pl"
Resume koniec
End Sub

Podobnie modyfikuje się wstążkę dla otwartej wiadomości.

(c) Shon Oskar – www.VBATools.pl

Wszelkie prawa zastrzeżone. Żadna część ani całość tego artykułu nie może być powielana ani publikowana bez zgody autora.

Skomentuj przejdź do artykułu ...

Lista poprawności z innego pliku

napisane przez Oskar w dniu wtorek, 14 Luty, 2012, w kategorii Porady - Excel

Aby zastosować listę poprawności z innej lokalizacji w arkuszu należy użyć nazwy zakresu. Wywołuje się jej nadanie po przez [Ctrl+F3], a następnie wstawienie jej w pola adresu listy. Jeśli jednak chodzi o położenie danych jaką chcemy zastosować w liście poprawności, która znajduje się w osobnym pliku, należy zastosować procedurę VBA.

Wygląda to w następujący sposób.

 Option Explicit

Sub Validation_2ndFile_range()
'MVP OShon from VBATools.pl
 Dim a$, el As Range, wkb As Workbook, wks As Worksheet
 Dim rng1 As Range
 Set wkb = Workbooks("1.xlsx") 'inny skoroszyt
 Set wks = wkb.Sheets("Arkusz1") 'arkusz skoroszytu
 Set rng1 = wks.Range("a1:a10")
 For Each el In rng1
  a = a & el.Value & ","
 Next
 With Range("A1").Validation 'docelowa lista
  .Delete
  .Add Type:=xlValidateList, Formula1:=a
 End With
 Set rng1 = Nothing
 Set wks = Nothing
 Set wkb = Nothing
End Sub

Oto widok zastosowania:

 

(c) Shon Oskar – www.VBATools.pl

Wszelkie prawa zastrzeżone. Żadna część ani całość tego artykułu nie może być powielana ani publikowana bez zgody autora.

Skomentuj przejdź do artykułu ...

Połączenie danych z osobnych kolumn

napisane przez Oskar w dniu poniedziałek, 13 Luty, 2012, w kategorii Porady - Excel

Zastanawiacie się jak szybko połączyć dane z zakresów? Możecie oczywiście skorzystać z formuły złącz.teksty() jednakże kiedy mamy do czynienia z większymi zakresami musielibyście wykonać kopie formuły na całym zakresie w osobnej komunie, zamienić wynik na wartości, a następnie usunąć poprzednio wykorzystane w formule kolumny.

Poniżej można znaleźć metodę wykorzystującą unie zakresów, dzięki której szybko pobierzecie dane do pamięci, a w następnym kroku w miejsce danych wstawi połączone z zakresów dane.

Sub polaczenie_zakresow()
 Const kol1 As String = "C" 'dane z kolumny C
 Const kol2 As String = "D" 'dane z kolumny D
 Dim RR As Range, n As Long, x As Long, last_row&
 last_row = Cells(Rows.Count, kol1).End(xlUp).Row
 Set RR = Application.Union(Range(kol1 & "1:" & kol1 & last_row), _
 Range(kol2 & "1:" & kol2 & last_row))
 For x = 1 To RR.Count Step 2
   n = n + 1
   Cells(n, kol1) = RR(x) & RR(x + 1)
   Cells(n, kol2).ClearContents
 Next x
 Set RR = Nothing
End Sub

Zastosowanie makra ilustruje poniższy rysunek:

(c) Shon Oskar – www.VBATools.pl

Wszelkie prawa zastrzeżone. Żadna część ani całość tego artykułu nie może być powielana ani publikowana bez zgody autora.

Skomentuj przejdź do artykułu ...

Podgląd treści wiadomości.

napisane przez Oskar w dniu środa, 1 Luty, 2012, w kategorii Porady - Outlook

Często podczas automatyzacji chcemy się odwołać do treści wiadomości, jednak jak ją podglądnąć? Aby przetestować kontent najlepiej jest wyświetlić treść w oknie immediate. Samo okno wywołujemy przy pomocy skrótu klawiszowego [Ctrl+G] lub wybieramy z menu developera VBA.

Poniższa procedura pobiera dla zaznaczonej wiadomości lub otwartej i aktywnie wskazanej treść w postaci czystego tekstu lub kodu PHP, jaki stosowany jest w wiadomościach HTML.

Sub kotku_co_masz_w_srodku()
'MVP OShon from VBATools.pl
 Dim oMail As MailItem
 On Error GoTo koniec
 Select Case TypeName(Application.ActiveWindow)
 Case "Explorer":  Set oMail = ActiveExplorer.Selection.Item(1)
 Case "Inspector": Set oMail = ActiveInspector.CurrentItem
 Case Else: Exit Sub
 End Select
If oMail.BodyFormat = olFormatHTML Then
 Debug.Print oMail.HTMLBody
Else
 Debug.Print oMail.Body
End If
 Set oMail = Nothing
 Exit Sub
koniec:
 MsgBox Err.Number & " " & Err.Description, vbExclamation, "VBATools.pl"
End Sub

Dalsza obróbka może być przeprowadzona przy pomocy funkcji instr(), operatora like lub przekazania wartości przełącznika dla podjęcia dalszych działań.

(c) Shon Oskar – www.VBATools.pl

Wszelkie prawa zastrzeżone. Żadna część ani całość tego artykułu nie może być powielana ani publikowana bez zgody autora

Skomentuj przejdź do artykułu ...