win32com und BSTR

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
PureImpact
User
Beiträge: 15
Registriert: Donnerstag 13. April 2006, 19:20

Hallo liebe Leute,

erstes Posting und gleich ne Frage. Das Problem frisst mir schon seit Tagen die Nerven, doch nun scheint der Fehler eingegrenzt.
Es geht sich um folgendes...

Ich habe ein Programm namens MaxIm DL (http://www.cyanogen.com/products/maxim_main.htm) was eine CCD-Kamera steuern kann. Dieses Programm laesst sich wunderbar mittels vbscript steuern. Der "selbe" code in Python jedoch scheitert. Folgendes will ich machen: Ein Bild mittels der CCD-Kamera aufnehmen und es abspeichern. Beim Abspeichern krieg ich aber ne Fehlermeldung.

Code: Alles auswählen

import win32com.client, time

CCDCamera = win32com.client.Dispatch('MaxIm.CCDCamera')

CCDCamera.LinkEnabled = True

if CCDCamera.LinkEnabled == False:
     print 'Failed to start camera.'

exp = int(raw_input('Exposition[sec]: '))

CCDCamera.Expose(exp, 1, 0)
while CCDCamera.ImageReady == False:
     time.sleep
print 'Done'
time.sleep(3)
CCDCamera.SaveImage('S:/Reiner/MaxIm/1.fit')
Fehlermeldung:
---
Traceback (most recent call last):
File "S:/Reiner/MaxIm/maxim1.py", line 17, in ?
CCDCamera.SaveImage('S:/Reiner/MaxIm/1.fit')
File "C:\Programme\Python24\Lib\site-packages\win32com\client\dynamic.py", line 491, in __getattr__
raise pythoncom.com_error, details
com_error: (-2147352567, 'Ausnahmefehler aufgetreten.', (65535, 'MaxIm DL 4', 'Invalid Input', None, 0, 0), None)
---

Das Problem scheint also an dem Pfad+Dateinamen zu liegen der an die Methode SaveImage gegeben wird. Die Hilfe von MaxIm sagt folgendes:
---
SaveImage
Syntax

CCDCamera.SaveImage ( FilePath )

Parameters

BSTR FilePath – path to save file in

Returns

Boolean – True if successful
---

Eine andere Methode, wo man auch einen Pfad+Dateinamen uebermitteln muss, funktioniert jedoch. So kann ich ein bereits abgespeichertes Bild als Document-Objekt oeffnen, vertikal flippen und wieder abspeichern:

Code: Alles auswählen

import win32com.client

CCDCamera = win32com.client.dynamic.Dispatch('MaxIm.CCDCamera')
Document = win32com.client.dynamic.Dispatch('MaxIm.Document')
Application = win32com.client.dynamic.Dispatch('MaxIm.Application')

Document.OpenFile('S:/Reiner/MaxIm/t1.fit')
Document.Flip()
Document.SaveFile('S:/Reiner/MaxIm/t2.fit', 3, False, 1)
Auch alle anderen Methoden und Properties funktionieren.
Was ist also bei SaveImage anders?

Mir ist aufgefallen dass in der Hilfe unter SaveFile folgendes steht:
---
SaveFile
Syntax

Document.SaveFile ( FilePath, FileFormat, AutoStretch[, SizeFormat, CompressionType ])

Parameters

String FilePath - specifies the name of the image file to be written

usw.
---

D.h. er will hier ein String. Bei SaveImage wollte er aber ein BSTR.
Ich vermute daher dass es daran liegt. Wie kann ich also dafuer sorgen,
dass Pfad+Dateiname als BSTR uebermittelt werden?

Die Entwickler von MaxIm verstehen von Python leider nichts und koennen mir daher nicht weiterhelfen. Einer schrieb jedoch:

---
For CCDCamera.SaveImage, 'Invalid Input' is reported only if the argument is
not of an acceptable type. As you are probably aware from looking at the
type library, the filename argument is declared as a variant. What the type
library doesn't tell you is that the variant must be either a BSTR (unicode
string with header) or a reference to a BSTR. Specifically, the 'vt' member
of the VARIANT must be either VT_BSTR or VT_BSTR|VT_BYREF.

Does python provide any way of influencing how arguments for COM methods are
created? If so, you may be able to get this to work. It may be as simple
as assigning the string to a variable name instead of passing it as a
literal, or perhaps there's something equivalent to a C++ cast operator or a
VB 'type' function (CInt, CStr, etc.).
---

Ist dieses Problem bei Python und COM eventuell schon bekannt und gibt es dazu eine Loesung? Ich habe zunaechst hier im Forum gesucht (nach BSTR), allerdings nur ein topic gefunden wo es praktisch vorkam:
http://www.python-forum.de/topic-3078.h ... light=bstr

Ich benutze allerdings bereits das build 208.
Woran liegt es nun dass man nicht einfach einen String angeben kann,
wie bei der Methode SaveFile auch, der dann richtig an das COM-Objekt uebermittelt wird und wenn tatsaechlich noetig, wie generiert man einen BSTR string, wenn es denn einer sein muss und win32com dies nicht automatisch macht?

Danke,
Reiner :roll:
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

PureImpact hat geschrieben:Dieses Programm laesst sich wunderbar mittels vbscript steuern.
Hi Reiner!

1. Dann zeig uns doch bitte auch den funktionierenden VBS-Code. ;-)

2. Zeile 14: sleep ohne Klammern und Angabe der Zeit die gewartet werden soll.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

3: Vielleicht hilft es, wie bei einigen COM-Programmen, nicht nur "CCDCamera" sondern auch die anderen zugehörigen Programmteile zu initialisieren.

Code: Alles auswählen

CCDCamera = win32com.client.dynamic.Dispatch('MaxIm.CCDCamera')
Document = win32com.client.dynamic.Dispatch('MaxIm.Document')
Application = win32com.client.dynamic.Dispatch('MaxIm.Application') 
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
PureImpact
User
Beiträge: 15
Registriert: Donnerstag 13. April 2006, 19:20

Hallo,
gerold hat geschrieben:1. Dann zeig uns doch bitte auch den funktionierenden VBS-Code. ;-)

2. Zeile 14: sleep ohne Klammern und Angabe der Zeit die gewartet werden soll.
Gerne.

---

Code: Alles auswählen

Dim cam
Set cam = CreateObject("MaxIm.CCDCamera")
cam.LinkEnabled = True
if Not cam.LinkEnabled Then
wscript.echo "Failed to start camera."
Quit
End If
wscript.echo "Camera is ready, Exposing."
cam.Expose 1, 1, 0 
Do While Not cam.ImageReady
Loop
cam.SaveImage "S:\Reiner\MaxIm\1.fit"
wscript.echo "Exposure is done, Image saved as 1.fit"
---

Jau, doch er meckert wegen des Sleeps nicht. Und selbst wenn ich alle 1s checke ob die Kamera wieder ready ist, oder immer noch belichtet und falls not ready weiter schlafe, so klappt es auch und er steigt immer erst bei SaveImage aus.

Zur Info. Mark Hammond hat mittlerwile geantwortet dass:

---
Python will *always* (unless an object's typelib indicated otherwise) pass a
VT_BSTR when a string literal is specified. I'm afraid I can't speculate on
what the problem may otherwise be.
---

Der Autor von MaxIm hat geantwortet:

---
That is quite strange, since CCDCamera.SaveImage and Document.SaveFile
declare their filename arguments identically, in (1) the C++ source code,
(2) the dispatch table, and (3) the ODL file. I can't explain it.
---

Also was haben wir?

1. SaveFile, OpenFile und SaveImage declare their arguments identically...
2. Python will *always* (unless an object's typelib indicated otherwise) pass a VT_BSTR when a string literal is specified.
3. Allerdings: OpenFile und SaveFile geht, SaveImage nicht.

---> Kann nicht sein!

Ich habe in PythonWin im COM Object Browser mir mal die besagten functions angeschaut. Es sieht alles gut aus, d.h. das Argument ist Variant, so wie es wirklich sein soll. Ich gehe also davon aus dass win32com das benutzt, was die Objekte/Methoden haben wollen.
Den einzigen Unterschied den ich sehen kann, ist, dass SaveFile und OpenFile (die beiden funktionierenden Methoden) als Return Type ein "Void" haben, also nix soweit ich weiss, waehrend SaveImage als Return Type ein "BOOL" hat. Sollte das der Knackpunkt sein? Doch laut com_error ist es ja ein "Invalid Input", also das, was von win32com.client kommt, wird bemaengelt.

Meine Vermutung ist, dass entgegen der Aussage des MaxIm-Entwicklers, es doch eventuell einen kleinen Unterschied gibt in der Art wie SaveImage und SaveFile/OpenFile implementiert wurden. Sonst kann ich mir das alles nicht erklaeren, wieso das erste nicht klappt und die anderen klappen.

Ich hatte mit einem anderen Programm mal eine aehnliche Erfahrung. Nun ja, vielleicht nicht ganz vergleichbar. Dort hatte ein Objekt namens Plate eine Methode namens Solve().
In vbscript funktionierte Plate.Solve
In Python hingegen musste es, wie in der Programm-Hilfe auch spezifiziert natuerlich Plate.Solve() heissen. Bei Plate.Solve (d.h. ohne Klammern) machte das Python-Skript an dieser Stelle einfach *nichts*, zumindest nichts sichtbares. Es wurde kein Fehler ausgeloest, obwohl Solve() nicht ausgefuehrt wurde.

Daher meine Vermutung dass es doch was sein koennte was man von vbscript aus nicht erkennt, weil es dort einfach geht auch wenn man "schlampig" codiert, Python aber meckert weil es "pingeliger" ist. Was meint ihr?

Reiner
P.S.: Das Initialisieren der anderen zwei Objekte hilft leider nicht.
P.P.S.: Unten die Screenshots aus dem COM Object Browser, falls es klappt. Hmm, muss erst schauen wie man hier Bilder hochladen kann, wenn es ueberhaupt erlaubt ist.

Edit by Gerold: Den Code in Code-Tags getan, damit man es besser lesen kann
PureImpact
User
Beiträge: 15
Registriert: Donnerstag 13. April 2006, 19:20

PureImpact hat geschrieben:P.P.S.: Unten die Screenshots aus dem COM Object Browser, falls es klappt. Hmm, muss erst schauen wie man hier Bilder hochladen kann, wenn es ueberhaupt erlaubt ist.
Gut, habe in den FAQ gesehen dass man nix direkt hochladen kann, sondern nur verlinken. Also dann so:

Bild
Bild

R.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hi Reiner!

Das ist nur eine Vermutung, an der ich ansetzen würde. Bitte probier diesen Code aus:

Code: Alles auswählen

import win32com.client
import time

cam = win32com.client.Dispatch('MaxIm.CCDCamera')

try:
    cam.LinkEnabled(True)
except:
    cam.LinkEnabled = True

exp = int(raw_input('Exposition[sec]: '))

cam.Expose(exp, 1, 0)

while not cam.ImageReady():
    time.sleep(1)

print 'Done'
time.sleep(3)

cam.SaveImage(r'S:\Reiner\MaxIm\1.fit')
Geht das nicht, dann drehen wir noch an einem Rädchen:

Code: Alles auswählen

import win32com.client
import time

cam = win32com.client.Dispatch('MaxIm.CCDCamera')

cam.LinkEnabled = True

exp = int(raw_input('Exposition[sec]: '))

cam.Expose(exp, 1, 0)

while not cam.ImageReady():
    time.sleep(1)

print 'Done'
time.sleep(3)

cam.SaveImage(r'S:\Reiner\MaxIm\1.fit')
Mehr fällt mir im Moment nicht ein. Ich kann es ja nicht testen.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
PureImpact
User
Beiträge: 15
Registriert: Donnerstag 13. April 2006, 19:20

gerold hat geschrieben:

Code: Alles auswählen

import win32com.client
import time

cam = win32com.client.Dispatch('MaxIm.CCDCamera')

try:
    cam.LinkEnabled(True)
except:
    cam.LinkEnabled = True

exp = int(raw_input('Exposition[sec]: '))

cam.Expose(exp, 1, 0)

while not cam.ImageReady():
    time.sleep(1)

print 'Done'
time.sleep(3)

cam.SaveImage(r'S:\Reiner\MaxIm\1.fit')
---
Traceback (most recent call last):
File "S:/Reiner/MaxIm/maxim3.py", line 15, in ?
while not cam.ImageReady():
TypeError: 'bool' object is not callable
---
gerold hat geschrieben:

Code: Alles auswählen

import win32com.client
import time

cam = win32com.client.Dispatch('MaxIm.CCDCamera')

cam.LinkEnabled = True

exp = int(raw_input('Exposition[sec]: '))

cam.Expose(exp, 1, 0)

while not cam.ImageReady():
    time.sleep(1)

print 'Done'
time.sleep(3)

cam.SaveImage(r'S:\Reiner\MaxIm\1.fit')
---
Traceback (most recent call last):
File "S:/Reiner/MaxIm/maxim4.py", line 12, in ?
while not cam.ImageReady():
TypeError: 'bool' object is not callable
---

Okay, ich habe mal obigen Fehler behoben und es so gemacht:

Code: Alles auswählen

import win32com.client 
import time 

cam = win32com.client.Dispatch('MaxIm.CCDCamera') 

try: 
    cam.LinkEnabled(True) 
except: 
    cam.LinkEnabled = True 

exp = int(raw_input('Exposition[sec]: ')) 

cam.Expose(exp, 1, 0) 

#while not cam.ImageReady(): 
#    time.sleep(1) 
while cam.ImageReady == False:
    time.sleep

print 'Done' 
time.sleep(3) 

cam.SaveImage(r'S:\Reiner\MaxIm\1.fit')
Und:

Code: Alles auswählen

import win32com.client 
import time 

cam = win32com.client.Dispatch('MaxIm.CCDCamera') 

cam.LinkEnabled = True 

exp = int(raw_input('Exposition[sec]: ')) 

cam.Expose(exp, 1, 0) 

#while not cam.ImageReady(): 
#    time.sleep(1) 
while cam.ImageReady == False:
    time.sleep

print 'Done' 
time.sleep(3) 

cam.SaveImage(r'S:\Reiner\MaxIm\1.fit')
BTW, time.Sleep() geht nicht. Er meint dann:
"TypeError: sleep() takes exactly 1 argument (0 given)"

Wie auch immer, es meckert immer noch wegen des SaveImage:

---
Traceback (most recent call last):
File "S:/Reiner/MaxIm/maxim3.py", line 23, in ?
cam.SaveImage(r'S:\Reiner\MaxIm\1.fit')
File "C:\Programme\Python24\Lib\site-packages\win32com\client\dynamic.py", line 491, in __getattr__
raise pythoncom.com_error, details
com_error: (-2147352567, 'Ausnahmefehler aufgetreten.', (65535, 'MaxIm DL 4', 'Invalid Input', None, 0, 0), None)
---

und

---
Traceback (most recent call last):
File "S:/Reiner/MaxIm/maxim4.py", line 20, in ?
cam.SaveImage(r'S:\Reiner\MaxIm\1.fit')
File "C:\Programme\Python24\Lib\site-packages\win32com\client\dynamic.py", line 491, in __getattr__
raise pythoncom.com_error, details
com_error: (-2147352567, 'Ausnahmefehler aufgetreten.', (65535, 'MaxIm DL 4', 'Invalid Input', None, 0, 0), None)
---

Ich hatte solche Moeglichkeiten auch schon durchgespielt, wie \ statt / benutzen und dachte es laege doch irgendwie an dem ganzen encoding-Kram, den ich nicht wirklich verstehe. Hatte mir daher auch einige posts auf diesem Forum durchgelesen und bin so ueberhaupt erst darauf gestossen :wink:

Die Moeglichkeit besteht natuerlich immer noch, dass es was mit Unicode, cp-irgendwas und dem ganzen Krempel zu tun hat.
Jedoch funktioniert OpenFile ja, und dort schiebt man genauso einen normalen String rueber und es dudd.

Reiner
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Die Idee noch, dann gebe ich´s auf.

Code: Alles auswählen

cam.SaveImage(FilePath = "aaa") #Nur Dateiname
cam.SaveImage(FilePath = u"aaa")
cam.SaveImage(str("aaa"))
x = cam.SaveImage(str("aaa"))
s = "aaa"
cam.SaveImage(FilePath = s)
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
PureImpact
User
Beiträge: 15
Registriert: Donnerstag 13. April 2006, 19:20

n'abend!
gerold hat geschrieben:

Code: Alles auswählen

cam.SaveImage(FilePath = "aaa") #Nur Dateiname
cam.SaveImage(FilePath = u"aaa")
cam.SaveImage(str("aaa"))
x = cam.SaveImage(str("aaa"))
s = "aaa"
cam.SaveImage(FilePath = s)
Einiges davon hatte ich leider auch schon versucht. Ohne Erfolg.
Die restlichen werde ich gleich versuchen, auch wenn... siehe unten...

Heute Abend erreichte mich auch wieder eine Antwort von einem
MaxIm DL-Entwickler und er schrieb folgendes, nachdem er extra
Python2.4.3 und PythonWin build208 installiert hat um sich die Sache
genauer anzuschauen (ein netter Service, muss ich sagen...):

---
I set a breakpoint inside MaxIm DL, trapping when CCDCamera.SaveImage was called. Guess what? The variant argument that was supposed to contain the filename was VT_ERROR. Little wonder we were rejecting the call.
---

Nun schaut es also doch so aus, als laege der Fehler bei PythonWin und nicht bei MaxIm DL. Also habe ich das auch mal an Mark Hammond via python-win32 gepostet. Mal schaun was er sagt.

Ich danke jedenfalls fuer die rege Teilnahme hier auf dem Forum. Wenn es tatsaechlich ein bug in PythonWin ist und er dadurch beseitigt werden sollte, so hat es sich wenigstens gelohnt, unser kollektives Kopfzerbrechen :wink:

VT_ERROR sagt mir nicht viel. Es hoert sich fuer mich aber so an als waere es nicht das, was von win32com.client kommen sollte und was MaxIm DL's CCDCamera-Objekt erwartet.

Gruss,
Reiner
PureImpact
User
Beiträge: 15
Registriert: Donnerstag 13. April 2006, 19:20

Uebrigens, der MaxIm DL-Mensch schrieb auch folgendes:

---
Next, I looked at PythonWin's object browser, per your instructions. But
here I see something different. I assume you're opening the "Registered
Type Libraries" category, expanding 'MaxIm.Objects', and 'Type Library'
within that again. What I see is a long list of entries saying,

'The type info can n... = 'The type info can not be loaded!'

I can't say whether this indicates a bug in PythonWin or whether my registry
is corrupted somehow.
---

Muss es also was heissen wenn solche Eintraege in der Type Library sind?
Ich habe sie jedenfalls auch bei anderen Applikationen die sich aber fehlerfrei scripten lassen, ohne solche Ausnahmefehler zu erzeugen.
Ausserdem, wie die Screenshots oben zeigen, "sieht" PythonWin die besagten Methoden ja richtig, also sollte doch auch ein richtiges Argument uebermittelt werden, oder nicht? Wie kann es also dazu kommen dass so ein VT_ERROR ruebergefunkt wird?

Reiner
PureImpact
User
Beiträge: 15
Registriert: Donnerstag 13. April 2006, 19:20

Gerold,
gerold hat geschrieben:

Code: Alles auswählen

cam.SaveImage(FilePath = "aaa") #Nur Dateiname
cam.SaveImage(FilePath = u"aaa")
cam.SaveImage(str("aaa"))
x = cam.SaveImage(str("aaa"))
s = "aaa"
cam.SaveImage(FilePath = s)
Ich habe nochmal all dies ausprobiert. Immer noch der gleiche Ausnahmefehler. :(

Reiner
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Also ich kann dir leider nichts zum Problem sagen, aber dieser Support hab ich jetzt echt noch nie erlebt. Der Supporter installiert sogar noch Python und testet das ganze noch.

Also das ist echt mal ein Support an dem sich andere ein Beispiel nehmen könnten.

Ich hoffe du findest das Problem bald.

Gruss Rayo
PureImpact
User
Beiträge: 15
Registriert: Donnerstag 13. April 2006, 19:20

Rayo,
rayo hat geschrieben:Also ich kann dir leider nichts zum Problem sagen, aber dieser Support hab ich jetzt echt noch nie erlebt. Der Supporter installiert sogar noch Python und testet das ganze noch.

Also das ist echt mal ein Support an dem sich andere ein Beispiel nehmen könnten.

Ich hoffe du findest das Problem bald.

Gruss Rayo
Und nicht nur das. Ich lese gerade von ihm dass er sogar versucht hat Python und pywin32 "from source" zu bauen, in der Hoffnung das ganze debuggen zu koennen. Allerdings ist es nicht ganz gelungen weil er nur VC6 hat und er meinte dass man wohl VC7 braucht fuer pywin32.
Auch lernt er nun Python ueber Ostern...
Da sich Python in Astronomy/Science mehr und mehr durchsetzt, kann dies jedenfalls nicht schaden :wink:

BTW, einen Perl code hat er mir geschickt und dort funktioniert die ganze Sache auch:

---
#!perl

$Cam = $WScript->CreateObject('MaxIm.CCDCamera');

$Cam->{LinkEnabled} = 1;

die 'Failed to start camera' unless $Cam->{LinkEnabled};

print "Exposure[sec]: ";
$exp = <>;
die "Need a number!" unless $exp =~ /^\s*\d+(\.\d*)?\s*$/;

$Cam->Expose( $exp, 1, 0 );
$WScript->sleep( 50 ) until $Cam->ImageReady;
print "Done\n";

$WScript->sleep( 3000 );
$Cam->SaveImage( 'C:/1.fit' );
---

Wenn Mark Hammond nun auch etwas Interesse zeigt und der bug tatsaechlich in PythonWin ist, dann schoepfe ich wieder Hoffnung.

Wenn sonst noch einer sich daran die Zaehne ausbeissen will:
Man kann sich ne 30d trial von MaxIm DL ziehen. Im Programm
zunaechst die Simulator Camera auswaehlen, in der CCD Setup page,
bevor man mit dem Skripten anfaengt.
http://www.cyanogen.com/downloads/maxim_main.htm

Reiner
Buell
User
Beiträge: 90
Registriert: Samstag 29. Oktober 2005, 14:17

Hallo,

auch wenn dich das wahrscheinlich nicht mehr so interessiert, analysiere ich trotzdem mal ein paar von dir gepostete Fehlermeldungen. Da ich selbst auch sehr viel mit COM Schnittstellen arbeite kommen mir die irgendwie bekannt vor:

1.
---
Traceback (most recent call last):
File "S:/Reiner/MaxIm/maxim3.py", line 15, in ?
while not cam.ImageReady():
TypeError: 'bool' object is not callable
---
ich vermute mal (kenne die MaxIm Funktionen nicht) dass die Funktion ImageReady entweder nicht boolean ist oder über die Schnittstelle nicht vermittelbar ist. Die fehlermeldung sagt ja ganz klar dass kein bool Object unter angegebener Speicheradresse gefunden wird.

2.
BTW, time.Sleep() geht nicht. Er meint dann:
"TypeError: sleep() takes exactly 1 argument (0 given)"

da haste einfach die Klammer und nen Wert vergessen

3.
---
Traceback (most recent call last):
File "S:/Reiner/MaxIm/maxim3.py", line 23, in ?
cam.SaveImage(r'S:\Reiner\MaxIm\1.fit')
File "C:\Programme\Python24\Lib\site-packages\win32com\client\dynamic.py", line 491, in __getattr__
raise pythoncom.com_error, details
com_error: (-2147352567, 'Ausnahmefehler aufgetreten.', (65535, 'MaxIm DL 4', 'Invalid Input', None, 0, 0), None)
---
gehört zu meinen abslouten "lieblings" COM Fehlermeldungen und sagt eigentlich nur, dass die über die COM Schnittstelle angesprochene Funktion nicht den richtigen Wert bzw nicht die richitge Form des Wertes bekommen hat oder keinen Wert zurück geben kann. Ich selbst hatte mal den Fall, dass eine über COM angesprochene Funktion ein true bzw false zurück geben wollte und die gleiche Fehlermeldung kam. Lösung des Problemes nach unzähligen WOCHEN:
nicht

Code: Alles auswählen

diesunddas.FunktionSowieso()
sondern

Code: Alles auswählen

erg = diesunddas.FunktionSowieso()
und schon ging es. Die Funktion muss ihren Rückgabewert irgendwo loswerden, kann sie dies nicht kommt es zu einem Ausnahmefehler. Streng genommen müsste man sagen durch Variable erg wurde Speicherplatz allokiert auf dem der Rückgabewert abgelegt werden kann.
Andererseits sehen mir die Backslashes im Pfad sehr verdächtig aus. Habe es selbst schon gehabt, dass man - wenn man den Pfad komplett angibt immer zwei \\ machen muss, weil einfach \ ein Sonderzeichen darstellt, dass man sonst benutzt um zB ein " in einen String zu bekommen ("blabla\"bla\"blabla" => blabla"bla"blabla), deswegen würde ich einfach mal \\ probieren, klingt zwar doof - is aber so.

Ansonsten noch maximale Erfolge, falls du dich mal wieder dran setzen solltest. Keine Ahnung ob meine obigen Tipps was bringen, aber das sind meine leidvollen erfahrungen mit COM Schnittstellen, arbeite mal mit ner dll, da wirds noch wilder.
Buell
User
Beiträge: 90
Registriert: Samstag 29. Oktober 2005, 14:17

PureImpact hat geschrieben:
PureImpact hat geschrieben:P.P.S.: Unten die Screenshots aus dem COM Object Browser, falls es klappt. Hmm, muss erst schauen wie man hier Bilder hochladen kann, wenn es ueberhaupt erlaubt ist.
Gut, habe in den FAQ gesehen dass man nix direkt hochladen kann, sondern nur verlinken. Also dann so:

Bild
Bild

R.
Noch ein Nachtrag:

habe mir grad noch deinen obigen Beitrag angesehen, im 2. Fenster steht ganz klar Return Type='BOOL' -> die Funktion hat einen Rückgabewert und den will sie "loswerden". Was Variant für ein Datentyp sein soll ist mir momentan nicht so ganz klar. Aber auf jeden würde das meine Vermutung bekräftigen. Probier einfach mal:

Code: Alles auswählen

erg = cam.SaveImage(r'S:\Reiner\MaxIm\1.fit')
Mir ist allerdings nicht so ganz klar übergibt man SaveImage den Ziel oder den Quellpfad? Bei Zielpfad würde das r natürlich vollkommen sinnlos sein, denn auf eine zu schreibende Datei nur einen Lesezugriff zu geben klingt irgendwie unlogisch.

Ach, und grad noch was gesehen, bei den Parametern steht lediglich FilePath also es wird nur ein String mit dem Pfad erwartet und ein setzen der Rechte ist nicht erforderlich, eher könnte das zu Fehlern führen.

also:

Code: Alles auswählen

erg = cam.SaveImage('S:\Reiner\MaxIm\1.fit')
oder sonst:

Code: Alles auswählen

erg = cam.SaveImage('S:\\Reiner\\MaxIm\\1.fit')
aber um ganz sicher zu gehen versuche mal in deinem "working directory" zu sepeichern, also ohne Pfadangabe
murph
User
Beiträge: 622
Registriert: Freitag 14. April 2006, 19:23
Kontaktdaten:

also mit der backslachgeschichte kenne ich mich aus^^

entweder:
path=r"c:\erster\ordner"
oder:
path="c:\\erster\\ordner"

die gänsefüßchen können immer durch apostrophe ausgewechselt werden.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Buell hat geschrieben:

Code: Alles auswählen

erg = cam.SaveImage(r'S:\Reiner\MaxIm\1.fit')
Mir ist allerdings nicht so ganz klar übergibt man SaveImage den Ziel oder den Quellpfad? Bei Zielpfad würde das r natürlich vollkommen sinnlos sein, denn auf eine zu schreibende Datei nur einen Lesezugriff zu geben klingt irgendwie unlogisch.
Das r hat in diesem Fall nichts mit 'read' zu tun sondern sagt, dass ein raw string folgt, das heisst ein String, in dem die '\' nicht interpretiert werden:

Code: Alles auswählen

>>> print 'C:\verzeichnis\name\datei.txt'
C:
  erzeichnis
ame\datei.txt
>>> print 'C:\\verzeichnis\\name\\datei.txt'
C:\verzeichnis\name\datei.txt
>>> print r'C:\verzeichnis\name\datei.txt'
C:\verzeichnis\name\datei.txt
>>> print r'C:\\verzeichnis\\name\\datei.txt'
C:\\verzeichnis\\name\\datei.txt
EDIT: Ich sehe jetzt erst murphs Post...
Buell
User
Beiträge: 90
Registriert: Samstag 29. Oktober 2005, 14:17

OK, das mit dem r hatte ich als "read" interpretiert, so ergibt das natürlich Sinn und die Backslash Geschichte wäre beantwortet. Bleibt eigentlich nur noch als Fehler, was ich vorher auch schon geschrieben habe, mit dem Rückgabewert der irgendwo hin muss.
PureImpact
User
Beiträge: 15
Registriert: Donnerstag 13. April 2006, 19:20

Hallo Leute,

wollte euch nur mitteilen dass das Problem mittlerweile geloest wurde.
Wie bereits gesagt, ein Entwickler von MaxIm DL hat sich Python +
pywin32 installiert und daraufhin hat Mark Hammond sich ne Trial-Version
von MaxIm DL installiert und die beiden haben den Fehler gefunden.

FYI, Auszuege aus den emails:

Mark:
---
I did that (mainly due to the effort by him trying to track this down!)

The problem turns out to be:

pywintypes.com_error: (-2147352567, 'Exception occurred.', (65535, 'MaxIm DL
4', 'Invalid Input', None, 0, 0), None)

This exception is being raised by Python calling Invoke with the correct
dispid, but with only INVOKE_PROPERTYGET and *not* DISPATCH_METHOD. The
"problem" is that Python's syntax does does distinguish between a property
and a method - so:

ob.foo()

is (roughly) equivalent to:

func_ob = getattr(ob, "foo")
func_ob()

so win32com struggles around this, with the short story being that only
certain error values are "acceptable" when a 'method' is accessed as a
'property'.

Currently, pywin32 only accepts the hresults (DISP_E_MEMBERNOTFOUND,
DISP_E_BADPARAMCOUNT, DISP_E_PARAMNOTOPTIONAL, DISP_E_TYPEMISMATCH and
E_INVALIDARG). MaxIM returns DISP_E_EXCEPTION, which is not in this list -
and actually should not be. DISP_E_EXCEPTION means extra exception info is
returned, as reflected in the final part of the above exception. Ideally,
pywin32 would indirect into the COM excepinfo structure to find the real
error info. Fortunately for me <wink>, even if pywin32 did sniff deeper, it
would find an error result of -1 (65535) or zero - so would still fail to
find one of its 'acceptable' error results to make the distinction between
'property' and 'method'.

So - the end result is that MaxIM really needs to return a more sane result
when only PROPERTYGET is (or zero args are) requested. If it is more
convenient for MaxIM to continue to return DISP_E_EXCEPTION and set the real
error in the extended error info, I could agree to make pywin32 handle that
case ;)
---

Antwort von MaxIm DL-Jungs:
---
Well, all this is most instructive. Among other things it explains why
MaxIm DL's Document.SaveFile method is usable from Python, while
CCDCamera.SaveImage is not. SaveFile is declared as type void, so MFC's
COleDispatchImpl::Invoke() detects the attempt to access it as a property
and returns DISP_E_BADPARAMCOUNT, causing pywin32 to revise how it calls it.
But SaveImage is declared as returning a bool, so pywin32's tentative (and,
from MaxIm DL's perspective, erroneous) call without arguments gets through
into our implementation of the function, which then objects to the VT_ERROR
value that CCmdTarget::PushStackArgs() had supplied for lack of anything
from the client.

Reiner and I had independently suspected the result type might have
something to do with it, but I at least had concentrated on the appearance
of the call, i.e., whether the result was being 'used' or not. This was
irrelevant, of course.

Reading MFC\SRC\OLEDISP1.CPP more closely than I ever remember doing before,
it also becomes clears that any method having a parameter of type other than
VARIANT will also fail with DISP_E_BADPARAMCOUNT, causing pywin32 to
recover. So by my reckoning, the only MaxIm DL methods that will *not* work
when called from Python are:
Document.SetFITSKey
Document.GetFITSKey
CCDCamera.SaveImage
CCDCamera.SetFITSKey
Application.CalAddBias
Application.CalAddDark
Application.CalAddFlat

All others either return void, or have at least one non-VARIANT argument, or
both.

The question remains, what to do about it? I don't think the C++
implementation of a method (that is, a C++ method of a CCmdTarget-derived
class vectored to from a dispatch table) can obtain the wFlags value passed
to Invoke(), so I can't distinguish this situation from one where the caller
specified DISPATCH_METHOD but failed to provide an argument. This means the
behaviour of our COM interface would have to change, presenting possible
backward-compatibility issues to [non-Python] users. Even more germane, I
don't know how my code can return an error indicator other than
DISP_E_EXCEPTION (which we don't do directly anyway; it's the work of
AfxThrowOleDispatchException()). But I'm willing to be instructed if anyone
knows a way... :-)

Another possibility is to change the calling sequence, or return type, for
the methods listed above, e.g., by changing VT_VARIANT to VT_LPSTR in those
cases where only strings are expected. But this is sure to cause grief for
some users (even though we have had complained about our use of variants in
this context). A less draconian solution is to provide alternate methods
with more pywin32-friendly calling sequences and perhaps eventually
deprecate the troublesome ones. But I should state that my boss is on
record as saying he wants to minimize the impact on MaxIm DL.
---

...und kurze Zeit spaeter ein addendum:
---
Is it too late to recover any of my lost self-respect? Of course the answer
is AfxThrowOleException().

I'm now in favour of adding code like

if ( FilePath.vt == VT_ERROR )
AfxThrowOleException( DISP_E_BADPARAMCOUNT );

to the troublesome methods I listed previously, and not worry about the fact
that this changes prior behaviour. After all, the code of anyone who
notices this change wasn't working before anyway.

I already tried this, and Reiner's script (and Mark's pywin32) work like a
charm.
---

Die naechste Version von MaxIm DL (v4.54) wird somit Python/pywin32-
compliant sein :D

Besten Dank an alle die sich hier auf dem Forum an dem Raetsel beteiligt
haben. In der Hoffnung dass dieser Thread dem ein oder anderen in
Zukunft helfen wird, poste ich es mal, damit Google es findet. Oh man,
sehr gutes "Deutsch" mal wieder :lol:

Gruss,
Reiner
Antworten