Genel Bakış
PtrSafe (PtrSafe keyword), Declare deyiminde kullanılan ve bildirimin 64 bit ortamda güvenle çalışacağını VBA derleyicisine bildiren anahtar sözcüktür. Windows API ya da başka bir DLL işlevini çağıran bildirimlerde, VBA7 (Excel 2010 ve sonrası) ile gelen bu sözcük yazılmazsa 64 bit Excel kodu derlemeyi reddeder. Eski ve yeni Excel sürümlerinin ikisinde de çalışan kod için genellikle #If VBA7 Then koşullu derlemesiyle birlikte kullanılır.
PtrSafe yazmak tek başına kodu düzeltmez; derleyiciye "bu bildirimi inceledim, işaretçi boyutundaki değerleri doğru türde tanımladım" demektir. Asıl düzeltme, adres ve tutamaç türündeki parametrelerin ve dönüş değerlerinin LongPtr olarak yazılmasıdır:
Bu örnek Windows API çağırdığı için burada çalıştırılmadı. Makroyu kendi bilgisayarınızda çalıştırırsanız Excel yarım saniye yanıt vermez, ardından B2 hücresine bekleme mesajı yazılır. 64 bit Excel'de #If VBA7 dalı derlenir ve PtrSafe içeren satır kullanılır; Excel 2007 gibi eski sürümlerde #Else dalı derlenir. Sleep'in parametresi 32 bit bir değer olduğu için Long olarak kalır, LongPtr'ye çevrilmesi gerekmez.
B2 hücresi Evet değerini alır; bu değer Excel'in PtrSafe sözcüğünü tanıyan VBA7 derleyicisini kullanıp kullanmadığını gösterir. B3 hücresindeki Hayır sonucu Excel'in 64 bit olup olmadığını, B4 hücresindeki 4 ise işaretçi boyutunu bayt olarak verir. 64 bit Excel'de boyut 8, 32 bit Excel'de 4'tür.
Integer için 2 ve Long için 4 bayt bulunur; bu iki türün boyutu Excel'in 32 ya da 64 bit olmasından etkilenmez. LongPtr ise ortama uyum sağlar ve B4 hücresinde 4 bayt görünür. LongLong satırında (Yok (32 bit)) 64 bit Excel'de 8 bayt boyutu, 32 bit Excel'de ise türün bulunmadığını bildiren metin çıkar.
Söz dizimi
PtrSafe ayrı bir deyim değildir; Declare deyiminde Sub ya da Function sözcüğünden hemen önce yazılır:
VBA
2 satır
[Public | Private] Declare PtrSafe Sub ad Lib "kitaplık" [Alias "takma_ad"] [([bağımsız_değişkenler])]
[Public | Private] Declare PtrSafe Function ad Lib "kitaplık" [Alias "takma_ad"] [([bağımsız_değişkenler])] [As dönüş_türü]
- Public / Private: bildirimin erişim düzeyi; isteğe bağlıdır. Standart modülde belirtilmezse bildirim Public kabul edilir. Sınıf ve sayfa modüllerinde yalnız Private kullanılabilir.
- PtrSafe: 64 bit uyumluluğunu bildirir; VBA7 çalıştıran Excel'de (2010 ve sonrası) bildirimde bulunması gerekir. Excel 2007 ve öncesi bu sözcüğü tanımaz.
- Sub / Function: çağrılan yordamın değer döndürüp döndürmediğini belirtir; zorunludur.
- ad: yordamı VBA'da çağıracağınız ad; zorunludur.
- Lib: işlevin bulunduğu DLL adı (kernel32, user32 gibi); zorunludur.
- Alias: DLL içindeki gerçek işlev adı; isteğe bağlıdır. VBA'daki ad DLL'dekinden farklıysa kullanılır.
- bağımsız_değişkenler: parametre listesi; isteğe bağlıdır. Genellikle ByVal ya da ByRef ile yazılır.
- dönüş_türü: Function için dönen değerin veri türü; isteğe bağlıdır, yazılmazsa Variant olur.
Neden gerekli ve ne anlama gelir
64 bit Excel'de bellek adresleri ve tutamaçlar (pencere, dosya, nesne tutamacı) 8 bayt uzunluğundadır; 32 bit Excel'de ise 4 bayttır. Bildirimde bu değerler Long olarak bırakılırsa 64 bit ortamda adres kesilir ve Excel çökebilir. Bu nedenle 64 bit Excel, PtrSafe içermeyen Declare satırında derleme hatası verir; hata, kodun 64 bit sistemler için gözden geçirilip bildirimlerin PtrSafe ile işaretlenmesi gerektiğini söyler.PtrSafe yazmak tek başına kodu düzeltmez; derleyiciye "bu bildirimi inceledim, işaretçi boyutundaki değerleri doğru türde tanımladım" demektir. Asıl düzeltme, adres ve tutamaç türündeki parametrelerin ve dönüş değerlerinin LongPtr olarak yazılmasıdır:
VBA
5 satır
#If VBA7 Then
Private Declare PtrSafe Function GetForegroundWindow Lib "user32" () As LongPtr
#Else
Private Declare Function GetForegroundWindow Lib "user32" () As Long
#End If
- LongPtr: 32 bit Excel'de 4 bayt, 64 bit Excel'de 8 bayt olan işaretçi türü; tutamaç ve adresler için kullanılır.
- LongLong: yalnız 64 bit Excel'de bulunan 8 baytlık tam sayı türü.
- Long: 32 bit değerler için (DWORD, int) her ortamda 4 bayt kalır; bu tür parametreleri değiştirmeniz gerekmez.
Koşullu derleme ile eski sürümlerle uyum
Excel 2007 ve öncesinde PtrSafe sözcüğü bilinmediği için bildirim derleme hatası verir. Aynı dosyanın her sürümde açılması gerekiyorsa #If VBA7 Then ... #Else ... #End If yapısı kullanılır. Derleyici yalnız geçerli dalı derler, diğer dalı yok sayar.- VBA7: Excel 2010 ve sonrasında (32 ya da 64 bit) True olan derleme sabitidir.
- Win64: yalnız 64 bit Excel'de True olan derleme sabitidir.
1. Sleep API bildirimi ve çağrısı
Windows'un kernel32 kitaplığındaki Sleep yordamı, belirtilen milisaniye kadar Excel'i bekletir. Aşağıdaki kodu standart modüle yapıştırın; Declare satırları modülün en üstünde, yordamlardan önce durmalıdır. Bildirim hem eski hem yeni Excel sürümlerinde derlenecek biçimde #If VBA7 ile yazılmıştır.
VBA
14 satır
Option Explicit
#If VBA7 Then
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#End If
Sub YarimSaniyeBekle()
' Excel'i 500 milisaniye bekletir
Sleep 500
' Bekleme bittikten sonra sayfaya not düşer
Worksheets("Sleep Çağrısı").Range("B2").Value = "Bekleme tamamlandı"
End Sub
PtrSafe
Formülünü incelemek için bir hücre seçin.| A | B | |
|---|---|---|
| 1 | Adım | Açıklama |
| 2 | Bekleme | |
| 3 | Bildirim | Declare PtrSafe Sub Sleep |
| 4 | Bekleme süresi (ms) | 500 |
Sleep ÇağrısıExcelDepo v1.0.0
2. Excel ortamını koşullu derleme sabitleriyle sorgulama
PtrSafe kullanıp kullanamayacağınızı belirleyen VBA7 ve Win64 derleme sabitlerini sayfaya yazan bir makro. Kodu standart modüle yapıştırın. Makro, işaretçi boyutunu da LongPtr ile ölçer; böylece Excel'in 32 ya da 64 bit olduğunu görebilirsiniz.
VBA
23 satır
Option Explicit
Sub OrtamBilgisiYaz()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Ortam Bilgisi")
#If VBA7 Then
Dim p As LongPtr
ws.Range("B2").Value = "Evet"
#Else
Dim p As Long
ws.Range("B2").Value = "Hayır"
#End If
#If Win64 Then
ws.Range("B3").Value = "Evet"
#Else
ws.Range("B3").Value = "Hayır"
#End If
' İşaretçi türünün bayt cinsinden boyutu
ws.Range("B4").Value = LenB(p)
End Sub
PtrSafe
Formülünü incelemek için bir hücre seçin.| A | B | |
|---|---|---|
| 1 | Ölçüt | Sonuç |
| 2 | VBA7 derleyicisi (Excel 2010 ve sonrası) | Evet |
| 3 | 64 bit Excel | Hayır |
| 4 | LongPtr boyutu (bayt) | 4 |
Ortam BilgisiExcelDepo v1.0.0
3. Veri türlerinin bayt boyutlarını karşılaştırma
Long, LongPtr ve LongLong türlerinin boyut farkını gösteren makro. Kodu standart modüle yapıştırın. LongLong yalnız 64 bit Excel'de bulunduğu için ilgili kısım #If Win64 ile korunur; 32 bit Excel'de de hatasız derlenir.
VBA
29 satır
Option Explicit
Sub BoyutlariYaz()
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Bayt Boyutları")
Dim i As Integer
Dim l As Long
#If VBA7 Then
Dim lp As LongPtr
#Else
Dim lp As Long
#End If
#If Win64 Then
Dim ll As LongLong
#End If
ws.Range("B2").Value = LenB(i)
ws.Range("B3").Value = LenB(l)
ws.Range("B4").Value = LenB(lp)
#If Win64 Then
ws.Range("B5").Value = LenB(ll)
#Else
ws.Range("B5").Value = "Yok (32 bit)"
#End If
End Sub
PtrSafe
Formülünü incelemek için bir hücre seçin.| A | B | |
|---|---|---|
| 1 | Veri türü | Bayt boyutu |
| 2 | Integer | 2 |
| 3 | Long | 4 |
| 4 | LongPtr | 4 |
| 5 | LongLong | Yok (32 bit) |
Bayt BoyutlarıExcelDepo v1.0.0
Kullanırken dikkat edin
- PtrSafe tek başına yeterli değildir: Declare satırına PtrSafe eklemek hatayı susturur ama tutamaç ve adres parametrelerini kendiliğinden düzeltmez. Pencere tutamacı, bellek adresi ve nesne işaretçisi gibi değerleri Long bırakırsanız 64 bit Excel'de veri kaybı olur ve Excel beklenmedik biçimde kapanabilir. Bu parametreleri LongPtr yapın.
- Eski sürümlerde derleme hatası: Excel 2007 ve öncesi PtrSafe sözcüğünü tanımaz ve söz dizimi hatası verir. Dosya eski sürümlerde de açılacaksa Declare satırlarını mutlaka #If VBA7 Then ve #Else dallarıyla ikiye ayırın.
- Declare yerleşimi: Standart modülde Declare satırları modülün başında, yordamlardan önce yer almalıdır. Sınıf modüllerinde, sayfa modüllerinde ve UserForm modüllerinde bildirim yalnız Private olabilir; Public bildirim için standart modül kullanın.
- Dönüştürme işlevi: Bir sayıyı işaretçi türüne çevirmeniz gerekirse CLngPtr işlevini kullanın. 64 bit ortamda CLng ile dönüştürmek 8 baytlık değeri 4 bayta sığdırmaya çalışır ve taşma hatası verebilir.
- Win64 sabitini doğru yorumlayın: Win64 sabiti Excel'in 64 bit olduğunu, Windows'un 64 bit olduğunu değil gösterir. 64 bit Windows üzerinde 32 bit Excel çalışıyorsa Win64 False, VBA7 ise Excel 2010 ve sonrasında True olur. Bu durumda PtrSafe gerekir, ama LongLong kullanılamaz.
- Kodu denemeden önce: Windows API çağıran makroları denemeden önce dosyanızı kaydedin. Yanlış tür ya da parametre sırası Excel'i anında kapatabilir ve kaydedilmemiş çalışmanız kaybolur.
- İlgili konular:
- Declare deyimi: DLL işlevlerini VBA'ya tanıtır, PtrSafe bu deyimin bir parçasıdır.
- LongPtr: 32 bit'te 4, 64 bit'te 8 bayt olan işaretçi veri türü.
- LongLong: yalnız 64 bit Excel'de bulunan 8 baytlık tam sayı türü.
- CLngPtr: bir ifadeyi LongPtr türüne çeviren işlev.
- #If...Then...#Else: koşullu derleme yönergesi.
- VBA7 ve Win64: koşullu derleme sabitleri.
- Alias: Declare deyiminde DLL'deki gerçek işlev adını belirtir.
- ByVal ve ByRef: parametrenin değer ya da başvuru olarak geçirilmesini belirler.
- VarPtr, ObjPtr ve StrPtr: değişken, nesne ve metin adresini veren, LongPtr döndüren işlevler.