Seite 1 von 1

ProcedureDLL: Map zurückgeben, bzw. Alternative zu Maps

Verfasst: 18.03.2011 19:45
von Mok
Hallo!
Mein Programm ruft eine Prozedur aus einer DLL auf, welche ein paar CPU-Flags (SSE1 - SSE3, SSSE3, MMX und Co.) abfragt und in einer Map abspeichert. Für einen Fall wie diesen sind Maps ja wie gemacht. Das Problem daran: Wie kann ich die Map returnen, sodass ich sie im aufrufenden Programm verwenden kann? Und wenn's funktionieren würde, könnte man diese DLL nur in PureBasic nutzen, da der Purebasic-Typ 'Map' wohl in anderen Programmiersprachen genutzt werden kann.
Jetzt frage ich mich: Gibt es noch eine andere Datenstruktur/Möglichkeit, welche ich hier nutzen könnte, um die Flags zurückzugeben? Das ganze sollte möglichst ohne viel ADTs passieren (also jetzt eine eigene HashMap programmieren, welche man dann auch noch in jedem Ruferprogramm definieren muss). Zuvor hab ich's mit Strings gemacht, allerdings gleich wieder weggemacht, weil Effizienz = 0.

Hier noch ein (nicht funktionierender) Code:

Code: Alles auswählen

 ;DLL-Code
ProcedureDLL GetCpuFlags()
  ; Code großteils aus dem CodeArchiv
  Global mmx.b   = 0 ;MMX
  Global dnow.b  = 0 ;3DNow!
  Global ednow.b = 0 ;ext3DNow!
  Global cmov.b  = 0 ;CMovCC
  Global sse.b   = 0 ; SSE
  Global sse2.b  = 0 ;SSE2
  Global sse3.b  = 0 ;SSE3
  Global ssse3.b = 0 ;SSSE3
  Global SSE41.b = 0 ;SSE4.1
  Global SSE42.b = 0 ;SSE4.2

  Global Bit0.l  = $1
  Global Bit9.l  = $200
  Global Bit15.l = $8000
  Global Bit21.l = $200000
  Global Bit23.l = $800000
  Global Bit25.l = $2000000
  Global Bit26.l = $4000000
  Global Bit30.l = $40000000
  Global Bit31.l = $80000000
  Global SSE41b.l = $80000
  Global SSE42b.l = $100000
  
          
  
      !mov eax,1h
      !cpuid
      !test edx,[v_Bit23]
      !jz l_nommx
      !mov [v_mmx],1
  NOMMX:
      !test edx,[v_Bit25] 
      !jz l_nosse
      !mov [v_sse],1
  NOSSE:
      !test edx,[v_Bit26] 
      !jz l_nosse2
      !mov [v_sse2],1
  NOSSE2:
      !test ecx,[v_Bit0]
      !jz l_nosse3
      !mov [v_sse3],1    
  NOSSE3:
      !test ecx,[v_Bit9]
      !jz l_nossse3
      !mov [v_ssse3],1 
  NOSSSE3:
      !test edx,[v_Bit15]    
      !jz l_nocmov
      !mov [v_cmov],1
  NOCMOV:       
      !mov eax,80000000h
      !cpuid
      !cmp eax,80000000h
      !jbe l_noext
  
      !mov eax,80000001h
      !cpuid
      !or eax,eax
      !je l_noext
      !test edx,[v_Bit31] 
      !jz l_noext
      !mov [v_dnow],1
      !test edx,[v_Bit30]  
      !jz l_noext
      !mov [v_ednow],1
  NOEXT:
      !test ecx,[v_SSE41b]
      !jz l_nosse41
      !mov [v_SSE41], 1
  NOSSE41:
      !test ecx,[v_SSE42b]
      !jz l_nosse42
      !mov [v_SSE42], 1
  NOSSE42:

  NewMap m.b();
  m("MMX") = MMX
  m("3DNow") = dnow
  m("ext3DNow") = ednow
  m("CMov") = cmov
  m("SSE") = SSE
  m("SSE2") = SSE2
  m("SSE3") = SSE3
  m("SSE41") = SSE41
  m("SSE42") = SSE42
  m("SSSE3") = ssse3
  
  ProcedureReturn @m()
  EndProcedure

Code: Alles auswählen

;Programmcode
If OpenLibrary (0,"cpu.dll")
  Prototype.i _GetCpuFlags()
  Global GetCpuFlags._GetCpuFlags = GetFunction(0,"GetCpuFlags")
Endif

Structure CPU
  Architecture.l
  Cores.b
  Map *Flags.b()
EndStructure
Define.CPU Processor
Processor\Flags() = GetCpuFlags()
  

Re: ProcedureDLL: Map zurückgeben, bzw. Alternative zu Maps

Verfasst: 18.03.2011 19:50
von ts-soft
Maps können nicht zurückgegeben werden, aber als Parameter können sie an Proceduren übergeben werden,
sollte unter umständen auch bei einer DLL funktionieren, einfach mal testen.

Re: ProcedureDLL: Map zurückgeben, bzw. Alternative zu Maps

Verfasst: 18.03.2011 19:52
von STARGÅTE
ProcedureDLL GetCpuFlags(Map m.b())
statt NewMap m.b() unten

und dann:

Define.CPU Processor
GetCpuFlags(Processor\Flags())

Re: ProcedureDLL: Map zurückgeben, bzw. Alternative zu Maps

Verfasst: 18.03.2011 19:54
von Mok
STARGÅTE hat geschrieben:ProcedureDLL GetCpuFlags(Map m.b())
statt NewMap m.b()
Gute Idee, wäre da selber garnicht draufgekommen :allright:
Aber wie sieht's, sagen wir mal in C++ aus? Wie soll ich da eine Map übergeben? (sag bloß std::map)

Re: ProcedureDLL: Map zurückgeben, bzw. Alternative zu Maps

Verfasst: 18.03.2011 19:56
von ts-soft
In c++ steht die PB Map ja gar nicht zur Verfügung, ist dort also nicht nutzbar.
Gibt keinen DLL HashMap standard Programmiersprachenübergreifend, sowas
mußt Du Dir wohl selber basteln.

Re: ProcedureDLL: Map zurückgeben, bzw. Alternative zu Maps

Verfasst: 18.03.2011 22:50
von Kevin
Mok hat geschrieben:
STARGÅTE hat geschrieben:ProcedureDLL GetCpuFlags(Map m.b())
statt NewMap m.b()
Gute Idee, wäre da selber garnicht draufgekommen :allright:
Aber wie sieht's, sagen wir mal in C++ aus? Wie soll ich da eine Map übergeben? (sag bloß std::map)
so geht's es vielleicht:

Code: Alles auswählen

Structure CPU
  Architecture.l
  Cores.b
  Map Flags.b()
EndStructure

;DLL-Code
ProcedureDLL GetCpuFlags()
  ; Code großteils aus dem CodeArchiv
  Global mmx.b   = 0 ;MMX
  Global dnow.b  = 0 ;3DNow!
  Global ednow.b = 0 ;ext3DNow!
  Global cmov.b  = 0 ;CMovCC
  Global sse.b   = 0 ; SSE
  Global sse2.b  = 0 ;SSE2
  Global sse3.b  = 0 ;SSE3
  Global ssse3.b = 0 ;SSSE3
  Global SSE41.b = 0 ;SSE4.1
  Global SSE42.b = 0 ;SSE4.2

  Global Bit0.l  = $1
  Global Bit9.l  = $200
  Global Bit15.l = $8000
  Global Bit21.l = $200000
  Global Bit23.l = $800000
  Global Bit25.l = $2000000
  Global Bit26.l = $4000000
  Global Bit30.l = $40000000
  Global Bit31.l = $80000000
  Global SSE41b.l = $80000
  Global SSE42b.l = $100000
  
          
  
      !mov eax,1h
      !cpuid
      !test edx,[v_Bit23]
      !jz l_nommx
      !mov [v_mmx],1
  NOMMX:
      !test edx,[v_Bit25] 
      !jz l_nosse
      !mov [v_sse],1
  NOSSE:
      !test edx,[v_Bit26] 
      !jz l_nosse2
      !mov [v_sse2],1
  NOSSE2:
      !test ecx,[v_Bit0]
      !jz l_nosse3
      !mov [v_sse3],1    
  NOSSE3:
      !test ecx,[v_Bit9]
      !jz l_nossse3
      !mov [v_ssse3],1 
  NOSSSE3:
      !test edx,[v_Bit15]    
      !jz l_nocmov
      !mov [v_cmov],1
  NOCMOV:       
      !mov eax,80000000h
      !cpuid
      !cmp eax,80000000h
      !jbe l_noext
  
      !mov eax,80000001h
      !cpuid
      !or eax,eax
      !je l_noext
      !test edx,[v_Bit31] 
      !jz l_noext
      !mov [v_dnow],1
      !test edx,[v_Bit30]  
      !jz l_noext
      !mov [v_ednow],1
  NOEXT:
      !test ecx,[v_SSE41b]
      !jz l_nosse41
      !mov [v_SSE41], 1
  NOSSE41:
      !test ecx,[v_SSE42b]
      !jz l_nosse42
      !mov [v_SSE42], 1
  NOSSE42:

*CPU.CPU=AllocateMemory(SizeOf(CPU))
InitializeStructure(*CPU, CPU)

 *CPU\Flags("MMX") = MMX
 *CPU\Flags("3DNow") = dnow
 *CPU\Flags("ext3DNow") = ednow
 *CPU\Flags("CMov") = cmov
 *CPU\Flags("SSE") = SSE
 *CPU\Flags("SSE2") = SSE2
 *CPU\Flags("SSE3") = SSE3
 *CPU\Flags("SSE41") = SSE41
 *CPU\Flags("SSE42") = SSE42
 *CPU\Flags("SSSE3") = ssse3
  
  ProcedureReturn *CPU
  EndProcedure

ProcedureDLL CPUResetMap(*CPU.CPU)
  ProcedureReturn ResetMap(*CPU\Flags())
EndProcedure
ProcedureDLL.s CPUKey(*CPU.CPU)
  ProcedureReturn MapKey(*CPU\Flags())
EndProcedure
ProcedureDLL CPUFlag(*CPU.CPU,element$="")
  If element$
    ProcedureReturn *CPU\Flags(element$)
  Else
    ProcedureReturn *CPU\Flags()
  EndIf
EndProcedure
ProcedureDLL CPUNextElement(*CPU.CPU)
  ProcedureReturn NextMapElement(*CPU\Flags())
EndProcedure
ProcedureDLL CPUFree(*CPU.CPU)
  FreeMemory(*CPU)
EndProcedure

Define.CPU *Processor
*Processor = GetCpuFlags()

CPUResetMap(*Processor)
While CPUNextElement(*Processor)
  Debug CPUKey(*Processor) + ": " + Str(CPUFlag(*Processor))
Wend

Debug ""
Debug "MMX: "+Str(CPUFlag(*Processor,"SSE3"))
Debug "SSE3: "+Str(CPUFlag(*Processor,"SSE3"))

CPUFree(*Processor)

Re: ProcedureDLL: Map zurückgeben, bzw. Alternative zu Maps

Verfasst: 19.03.2011 13:44
von mk-soft
Bei Übergabe von Arrays an C++ oder dotNet würde ich "Variant von Type Array" empfehlen.
Das Aufräumen des speichers übernimmt dann auch das Gabage von C++ oder dotNet.

Code: Alles auswählen

Declare Unicode Function fcName Lib "PB.dll" (ByRef MyArray As Object) As Int32 ' hResult
Dim MyArray() as Object
Bei C++ muss es ähnlich sein

Code: Alles auswählen

IncludeFile "..\Funktionen\Varianthelper_Include.pb"

ProcedureDLL GetDaten_ArrayOfVariant(*var.variant)
  
  Protected *array.SAFEARRAY
  
  ; Falls noch Daten in der übergebenen variable vorhanden sind, diese löschen
  VariantClear(*var)
  ; Array erstellen (0..9)
  *array = saCreateSafeArray(#VT_VARIANT, 0, 10)
  ; Daten von array füllen
  V_STR(SA_VARIANT(*array, 0)) = T_BSTR("Hallo Welt")
  V_BOOL(SA_VARIANT(*array, 1)) = T_BOOL(#True)
  V_FLOAT(SA_VARIANT(*array, 2)) = 99.9
  V_LONG(SA_VARIANT(*array, 3)) = 12345678
  V_DATE(SA_VARIANT(*array, 4)) = T_DATE(Date())
  ;....
  
  ; Safearray zuweisten
  V_ARRAY_VARIANT(*var) = *array
  
EndProcedure

ProcedureDLL GetDaten_ArrayOfString(*var.variant)
  
  Protected *array.SAFEARRAY
  
  ; Falls noch Daten in der übergebenen variable vorhanden sind, diese löschen
  VariantClear(*var)
  ; Array erstellen (1..10)
  *array = saCreateSafeArray(#VT_BSTR, 5, 10)
  ; Daten von array füllen
  For i = saLBound(*array) To saUBound(*array)
    SA_BSTR(*array, i) = T_BSTR("Zeile " + Str(i))
  Next
  ;....
  
  ; Safearray zuweisten
  V_ARRAY_STR(*var) = *array
  
EndProcedure


VariantHelper