Seite 1 von 1

win32com und C++ ComObjekt

Verfasst: Dienstag 8. Februar 2005, 18:55
von intruder
Hallo,

ich habe mit C++ (VS 6.0) ein ComObjekt erstellt und möchte
dieses nun aus Python (2.2.1) heraus ansprechen.

Ich habe im IDL File eine struct definiert, welches ein SAFEARRAY(double)
beinhaltet.

Code: Alles auswählen

typedef
[
	uuid(19115fab-7e40-4505-9cc2-1a072fd4b033),
	version(1.0),
	helpstring("Vola Parameters for FITLib")
]	
struct VolaParams {
	[helpstring("Distribution")] long lDistribution;
	[helpstring("Type")] long lType;
	[helpstring("a CalFlag")] long  lACalFlag;
	[helpstring("b CalFlag")] long lBCalFlag;
	[helpstring("c CalFlag")] long lCCalFlag;
	[helpstring("d CalFlag")] long lDCalFlag;
	[helpstring("a")] double dA;
	[helpstring("b")] double dB;
	[helpstring("c")] double dC;
	[helpstring("d")] double dD;
	[helpstring("q")] double dQ;
	[helpstring("ks")] SAFEARRAY(double)	dKs;
} VolaParams;
im Pythoncode kann ich alle normalen Werte ganz einfach zuweisen, aber
dem Safearray kann ich leider nichts zuweisen, da gibt es immer einen Fehler

Code: Alles auswählen

import win32com.client

myCom = win32com.client.Dispatch("ComLib.FinLib")
myStruct = myCom.VolaPar
myStruct.dKs = (1,2,3,4,5)
Fehlermeldung:
Traceback (most recent call last):
File "C:\Visual Studio 6.0\com.py", line 6, in ?
myStruct.dKs = (1,2,3,4)
pywintypes.com_error: (-2147024809, 'Falscher Parameter.', None, None)

Weiß jemand wie ich dieses SafeArray in Python füllen kann?

Vielen Dank im Voraus

Christian

Verfasst: Dienstag 8. Februar 2005, 19:17
von Leonidas
Vielleicht muss du eine List ( [] ) und keine Tupel ( () ) nutzen.

Wieso lässt du Dateien für static Dispatch nicht von makepy machen?

Verfasst: Mittwoch 9. Februar 2005, 12:34
von intruder
Danke Leonidas,

aber leider hat mir auch makepy.py nicht weiter geholfen.
Ich benutze das gleiche ComInterface auch in VBA und dort kann
ich das SafeArray so füllen:

Code: Alles auswählen

Dim vp As Lib.Params
ReDim vp.dKs(UBound(params, 1))
Call Range2DblArray(params, vp.dKs)

# my vba fill function
Sub Range2DblArray(range As Variant, arr As Variant)
    'ReDim myArray(UBound(range, 1))
    Dim i As Integer
    '..
    For i = 1 To UBound(range, 1)
        arr(i) = CDbl(range(i, 1))
    Next i
    'Range2Array = myArray
End Sub
Ich habe auch schon versucht ein array zu erzeugen und dieses
dem tuple in der com_struct zu zuweisen, aber leider auch ohne erfolg.

Code: Alles auswählen

import array
a = array.array('d', [1.4, 3.4])
b = buffer(a)
rec.dKs = b
Ich beführchte fast, dass ich in meinem ComObjekt eine Zusatzfunktion einbauen muss, die mir das SafeArray füllt.

Vielen Dank
Christian

Verfasst: Mittwoch 9. Februar 2005, 13:04
von Leonidas
List != Array!

Probiers mal so:

Code: Alles auswählen

import win32com.client

myCom = win32com.client.Dispatch("ComLib.FinLib")
myStruct = myCom.VolaPar
myStruct.dKs = [1,2,3,4,5]
Oder du schickst es mir und ich guck mir das mal an..

Verfasst: Mittwoch 9. Februar 2005, 18:38
von intruder
So habe eine Lösung gefunden und zwar muss man ein VARIANT übergeben:

IDL Datei
-----------------------------------------------------------------------------------

Code: Alles auswählen

struct Param {
      [helpstring("q")] double dTest;
      [helpstring("ks")] VARIANT dArray;
} Param;
Dummy Method (C++)
----------------------------------------------------------------------------------

Code: Alles auswählen

STDMETHODIMP CTest::Dummy(Param *para, double *result)
{

      VARIANT variantArray = para->dArray;

      std::vector<double> localArray;

      double dItem = 0.0;
      long lVal[1];
      long i;

      VARIANT varItem;

      long lBound = 0;
      long uBound = 0;

      SafeArrayGetLBound(variantArray.parray,1,&lBound);
      SafeArrayGetUBound(variantArray.parray,1,&uBound);

      for (i=lBound;i <= uBound; i++)
      {
            lVal[0] = i;
            SafeArrayGetElement(variantArray.parray, lVal, &varItem);

            if (varItem.vt == VT_R8)
                  localArray.push_back(varItem.dblVal);
      }

      *result = localArray[0];

      return S_OK;
}
PyCrust / Python Call
-----------------------------------------------------------------------------------

Code: Alles auswählen

import win32com.client
myCom = win32com.client.Dispatch("Com.Test")
myRec = win32com.client.Record('Param', myCom)
myRec.dArray = (1.0, 2.0, 3.0)
result = myCom.Dummy(myRec)
result
1.0
myRec.dArray = (4.5670, 2.0, 3.0)
result = myCom.Dummy(myRec)
result
4.5670000000000002
Gruß
Christian