दरअसल विफल रहता है, वहाँ स्मृति में सीमा मूल्यों संपादन का कोई सीधा रास्ता है। विस्तृत उत्तर और कार्ल के लिए धन्यवाद @AndASM; अच्छा हंच, यह स्पॉट-ऑन था। मुझे उस पल में सभी उलटाई में बहुत उलझन में होना चाहिए, Value2
भूलना सिर्फ एक संपत्ति है।
इस बीच, मैं OllyDbg के साथ कुछ अन्य परीक्षण और डिबगिंग के साथ एक सा गहरा delved और कुछ दिलचस्प बातें पाया:
- प्रकोष्ठों 16 x 1024 क्षेत्रों में व्यवस्थित कर रहे हैं। क्षेत्रों को रखने वाली संरचना वर्कशीट बहुत अच्छी तरह से हो सकती है, लेकिन मैं अभी तक पुष्टि नहीं कर सकता;
- हर बार
Value
संपत्ति लागू की जाती है, पूर्ण शीट ऑफ़सेट (पंक्ति, कॉलम) का उपयोग इसी क्षेत्र और को वास्तविक मूल्य प्राप्त करने के लिए क्षेत्र के अंदर कुछ अनुक्रमण के लिए किया जाता है; - प्रकार का एक 2 डी सुरक्षितता VARIANT बनाया गया है;
- मूल्य एक संगत ब्लॉक में, लेकिन व्यक्तिगत रूप से पुनर्प्राप्त नहीं किए जाते हैं। इसका मतलब है कि इंडेक्सिंग प्रक्रिया में प्रत्येक "बिंदु" को संबंधित SAFEARRAY तत्व के लिए मान (संस्करण, स्पष्ट रूप से) वापस करने के लिए भेजा गया है;
- उपर्युक्त के परिणामस्वरूप, प्रत्येक बार जब आप
Range.Value2(row,col)
के माध्यम से कोई मान पुनर्प्राप्त करते हैं, तो संपूर्ण प्रक्रिया को सभी सीमाओं के मानों के लिए दोहराया जाता है। यदि आप इस प्रक्रिया में कई बार एक प्रक्रिया के अंदर या इससे भी बदतर, एक लूप के अंदर प्रदर्शन प्रदर्शन की कल्पना कीजिए। बस मत करो; आप इंडेक्सिंग के जरिएValue2
और की प्रतिलिपि बनाने से बेहतर हैं; अंतिम, अभी तक कम से कम नहीं,
SAFEARRAY.pvData
अंदर मानों का वितरण स्तंभ आधारित(col,row)
, नहीं पंक्ति के आधार पर, पाया जा सकता है जिससे उसे प्रति सहज और VBA अनुक्रमण मोड है, जो(row,col)
है के साथ अंतर पर है। यदि आपको को स्मृति में सीधे पीवीडेटा तक पहुंचने और आयाम समेकन रखने की आवश्यकता है तो यह आसान हो सकता है। उदाहरण के लिए, नीचे1, 2, 3, 4 5, 6, 7, 8
एक निम्न क्रम में
pvData
में संग्रहीत किया जाएगा की तरह एक सीमा:1, 5, 2, 6, 3, 7, 4, 8
मुझे आशा है कि इसके बाद के संस्करण में मदद करता है। एक्सेल में ऐसे किसी भी निर्यात किए गए फ़ंक्शन की अनुपस्थिति में, Value2
की प्रतिलिपि बनाने के लिए सबसे अच्छा तरीका है, वांछित परिणाम की ओर सॉर्टिंग/मैनिपुलेट करना और इसे रेंज प्रॉपर्टी पर वापस असाइन करना।
मैंने हाल ही में क्विकॉर्ट का एक बदलाव पूरा किया है और एक्सेल के लिए लागू करने का इरादा रखता है। एल्गोरिदम प्रभावी है और वास्तव में एक ऐड-इन के रूप में मूल्य लाएगा, यदि सरणी मानों को सीमा में डालने पर अतिरिक्त समय के लिए नहीं किया गया है। ट्रांसपोज़िंग केवल 65537 से कम के लिए काम करता है, जबकि 'पेस्ट वेरिएंट-सरणी रेंज को बड़े प्रकार पर बहुत लंबा लगता है।
इसलिए, मैंने कुछ प्रक्रियाएं लिखीं जो 2 डी सरणी को 1 डी सरणी (सॉर्टिंग के लिए 1 डी की आवश्यकता है) में कॉपी करने की अनुमति देगी और (सॉर्टिंग के बाद) उन्हें वापस रखकर, सभी सुरक्षित और मेमकोपी पर आधारित हैं (RtlMoveMemory) और, वैकल्पिक रूप से, WriteProcessMemory।
सभी काम अच्छी तरह से काम करते हैं, जहां तक मेमोरी ऑपरेशंस का संबंध है: - रेंज मान सरणी में कॉपी किए जाते हैं (एक SafeArray.pvData से दूसरे तक); - सरणी मान (सॉर्टिंग अलगो चलाने के बाद) सफलतापूर्वक रेंज में कॉपी किए जाते हैं। Value2 SafeArray.pvData।
फिर भी, सीमा अद्यतन नहीं होती है, क्योंकि यह पुराने मानों (नीचे दिए गए कोड में अधिक) पर वापस जाने लगता है। "रेंज.वेल्यू 2 = कुछ अन्य 2 डीएरे" क्यों काम करेगा और सीधे मेमोरी में डेटा को संशोधित नहीं करेगा? मुझे एहसास है कि मुझे यहां कुछ याद आ रही है। एक फॉर्मूला सॉर्ट/अपडेट की आवश्यकता है, साथ ही?
Public Sub XLSORT_Array2()
With Application
screenUpdateState = .ScreenUpdating
statusBarState = .DisplayStatusBar
calcState = .Calculation
eventsState = .EnableEvents
.ScreenUpdating = False
.DisplayStatusBar = False
.Calculation = xlCalculationManual
.EnableEvents = False
End With
Dim rngSort As Range
Dim arrSort() As Variant
Dim arrTemp As Variant
Dim i As Long
Dim dblTime As Double
Dim dblInitTime As Double: dblInitTime = Timer
Set rngSort = Selection
If Not rngSort Is Nothing Then
If rngSort.Cells.Count > 1 And rngSort.Areas.Count = 1 Then
dblTime = Timer
ReDim arrSort(1 To rngSort.Cells.Count)
Debug.Print Timer - dblTime & vbTab & "(Redim)"
'just testing Excel memory location
'Debug.Print VarPtr(rngSort.Value2(1, 1))
dblTime = Timer
SA_Duplicate arrSort, rngSort.Value2
Debug.Print Timer - dblTime & vbTab & "(Copy)"
dblTime = Timer
SORTVAR_QSWrapper arrSort, 1, rngSort.Cells.Count
Debug.Print Timer - dblTime & vbTab & "(Sort)"
'this would be the fastest method
'variants are copied to memory
'yet the range does not update with the new values
SA_Duplicate rngSort.Value2, arrSort
'dblTime = Timer
'looping = too slow
'For i = 1 To rngSort.Cells.Count
' rngSort.Cells(i).Value = arrSort(i)
'Next
'this works, but it's too slow, as well
'If rngSort.Cells.Count > 65536 Then
' ReDim arrTemp(LBound(rngSort.Value2, 1) To UBound(rngSort.Value2, 1), LBound(rngSort.Value2, 2) To UBound(rngSort.Value2, 2))
' SA_Duplicate arrTemp, arrSort
' rngSort.Value2 = arrTemp
'Else
' rngSort.Value2 = WorksheetFunction.Transpose(arrSort)
' Debug.Print "Transposed"
'End If
'Debug.Print Timer - dblTime & vbTab & "(Paste)"
End If
End If
With Application
.ScreenUpdating = screenUpdateState
.DisplayStatusBar = statusBarState
.Calculation = calcState
.EnableEvents = eventsState
End With
Debug.Print VarPtr(rngSort.Value2(1, 1)) & vbTab & Mem_ReadHex(ByVal VarPtr(rngSort.Value2(1, 1)), rngSort.Cells.Count * 16)
Set rngSort = Nothing
Debug.Print Timer - dblInitTime & vbTab & "(Total Time)" & vbNewLine
End Sub
की सीमा में मूल्यों मान लीजिए 4 कर रहे हैं, 3, 2, और 1. SA_Duplicate arrSort, rngSort.Value2
से पहले स्मृति में लिखा है::
130836704 05000000 00000000 00000000 00001040 05000000 00000000 00000000 00000840 05000000 00000000 00000000 00000040 05000000 00000000 00000000 0000F03F
129997032 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
जहां 130836704
यहां मुख्य प्रक्रिया है Range.Value2 SafeArray.pvData
और 129997032
SortArray SafeArray.pvData
है। प्रत्येक 16-बाइट बैच वेरिएंट वास्तविक डेटा का प्रतिनिधित्व करता है, जैसा मेमोरी (कोई LE अनुवाद, केवल हेक्स में) से पढ़ा जाता है, वाराटाइप को इंगित करने वाले पहले 2 बाइट्स के साथ। इस मामले में, vbDouble।
प्रतिलिपि के बाद, उम्मीद के रूप में, स्मृति में लिखा है: प्रकार पूरा हो गया है
130836704 05000000 00000000 00000000 00001040 05000000 00000000 00000000 00000840 05000000 00000000 00000000 00000040 05000000 00000000 00000000 0000F03F
129997032 05000000 00000000 00000000 00001040 05000000 00000000 00000000 00000840 05000000 00000000 00000000 00000040 05000000 00000000 00000000 0000F03F
के बाद, SortArray SafeArray.pvData पढ़ता है:
129997032 05000000 00000000 00000000 0000F03F 05000000 00000000 00000000 00000040 05000000 00000000 00000000 00000840 05000000 00000000 00000000 00001040
SA_Duplicate rngSort.Value2, arrSort
को क्रियान्वित करने के बाद, याद है कि पता चलता है Range.Value2 SafeArray.pvData को अद्यतन किया गया है:
129997032 05000000 00000000 00000000 0000F03F 05000000 00000000 00000000 00000040 05000000 00000000 00000000 00000840 05000000 00000000 00000000 00001040
130836704 05000000 00000000 00000000 0000F03F 05000000 00000000 00000000 00000040 05000000 00000000 00000000 00000840 05000000 00000000 00000000 00001040
सभी अब तक ठीक लग रही, सिवाय इसके कि Debug.Print VarPtr(rngSort.Value2(1, 1)) & vbTab & Mem_ReadHex[...]
पता चलता है कि मूल्यों प्रारंभिक आदेश को वापस फ़्लिप किया गया:
130836704 05000000 00000000 00000000 00001040 05000000 00000000 00000000 00000840 05000000 00000000 00000000 00000040 05000000 00000000 00000000 0000F03F
कोई विचार या तरीकों आप प्रभावी पाया साझा करें। किसी भी मदद की सराहना की है। एक्सेल के लिए 4 सेकंड (1,000,000 + कोशिकाओं को सॉर्ट करना) की प्रतीक्षा करना निराशाजनक है, जब भी सबसे चुनौतीपूर्ण प्रकार उससे कम लेता है।
अग्रिम धन्यवाद!
मुझे लगता है कि यह जानना अंतर्दृष्टिपूर्ण हो सकता है कि SA_Duplicate क्या करता है, लेकिन जब से इसे रेंज करने के लिए सड़क को नीचे दिया जाता है। Value2 बस काम करता है, मुझे लगता है कि नया डेटा सही है? इसलिए मुझे संदेह है कि Excel आंतरिक रूप से किसी अन्य संरचना में सुरक्षित रूप से डेटा को रखता है, और वाल्यू /। वैल्यू 2 गुण केवल गोले हैं जो अनुवाद करते हैं; इसका मतलब यह होगा कि वेरिएंट की डायरेक्ट मेमोरी मैनिपुलेशन इन गुणों की वापसी व्यर्थ है। –