[Gelöst]Task für Automation ermitteln?

9. Dezember 2009 15:40

Hallo zusammen,

ich stehe vor einem kleinen Problem, und zwar erstelle ich gerade einen Mailversand aus Navision heraus, um vorher per Code erstellte PDF-Dateien zu versenden. Ich greife dabei auf Automation-Objekte zurück. Solange Outlook vorher geöffnet war, funktioniert das auch gut, aber wenn Outlook noch nicht läuft, krachts. Nun wäre meine Frage: Kann ich ermitteln, ob schon eine Outlook-Instanz läuft oder gibt es etwas in der Auotmation-Variable, was mir mitteilt, dass Outlook gestartet und einsatzbereit ist? Alternativ könnte ich es auch mit Sleep probieren, aber wir haben hier dermaßene Unterschiede im Startverhalten von Outlook dank großer Leistungsunterschiede der einzelnen Workstations, dass ich den Wert dann schon sehr lang bemessen müsste ...

Irgendjemand eine Idee?
Zuletzt geändert von CaddyM am 11. Dezember 2009 10:39, insgesamt 1-mal geändert.

Re: Task für Automation ermitteln?

9. Dezember 2009 15:49

Hallo CaddyM,

als Alternative zum Versand via Outlook gibt es ab Version 5
die Codeunit 400 "SMTP Mail". Du wärst damit unabhängig
von Outlook. Die C400 sendet direkt an einen SMTP-Server.

Es ist möglich, diese in Version 4 einzubinden.

Gruß Torsten

Re: Task für Automation ermitteln?

9. Dezember 2009 15:51

Hallo,

das wäre in diesem Fall nicht so sinnvoll, weil die User die Mail noch bearbeiten dürfen sollen - wenn das direkt an den SMTP geht ist das doch nicht mehr möglich, oder? Wäre dann ja quasi das gleiche wie die Send-Funktion des Outlook-Automation-Objekts ....

Re: Task für Automation ermitteln?

9. Dezember 2009 16:03

Ich denke das kann mit dem "Windows Scripting host" ermittelt werden, schau mal in der Hilfe, evtl. findest du etwas:
MSDynamics Suche - Scripting host

Re: Task für Automation ermitteln?

9. Dezember 2009 16:29

Prima - da muss ich gleich mal probieren, das hilft mir auf jeden Fall mal weiter.

Jetzt aber noch was: Wenn ich über die Automation Outlook gestartet habe - gibt es eine Möglichkeit, abzufrage, ob das Programm vollständig gestartet ist? Denn genau das scheint mein Problem zu sein, dass ich versuche ein Mailobjekt zu erstellen, ohne dass Outlook voll gestartet ist :roll:

Re: Task für Automation ermitteln?

9. Dezember 2009 17:31

Leider konnte ich auf die schnelle auch nichts finden, aber ein paar interessante links habe ich (ich denke Kap. 3 ist das richtige):
Microsoft® Windows® 2000 - Scripting-Handbuch
Kapitel 1 – Einführung in die Windows-Scripting-Technologien
Kapitel 2 – VBScript
Kapitel 3 – Der WSH
Kapitel 4 - Die Script-Laufzeitbibliothek
Kapitel 5 – ADSI-Scripting

**Edit by Mikka**
Dieses Seite habe ich gerade wiedergefunden, die finde ich auch ganz nett:
Sebastian Koch (quaschtel.de) - Windows Scripting Host

Re: Task für Automation ermitteln?

10. Dezember 2009 15:34

Hallo Mikka,

ja, da steht ne Menge nützlicher Tips drin. Aber das ist irgendwie noch nicht ganz das was ich suche. Ich hab hier mal meinen Code angehängt:

Code:
//Funktion sendAtachment(pFilename : Text[100]; pPath : Text[100]; pSubject : Text[250])
//Variablen:
// oApp (Automation, Microsoft Outlook 12.0 Object Library: Application)
// oAttachement ( Automation, Microsoft Outlook 12.0 Object Library: Attachment)
// oMailItem (Automation, Microsoft Outlook 12.0 Object Library: MailItem)

IF FILE.EXISTS(pPath + pFileName) THEN BEGIN

  IF ISCLEAR(oApp) THEN
    CREATE(oApp);

  oMailItem := oApp.CreateItem(0);  //Mailitem erstellen
  oMailItem.Attachments.Add(pPath+pFileName);
  oMailItem.Subject := pSubject;
  oMailItem.Recipients.Add('myMail@myDomain.de');
  oMailItem.Display;


END ELSE BEGIN
 //TODO: wenn die Datei nicht existiert / nicht zugegriffen werden kann
END;


Wie gesagt - das funktioniert wunderbar, solange Outlook vorher geöffnet war - war es das nicht, hängt sich die Verarbeitung weg. Ich denke es reicht irgendwie einen Weg zu finden, wie ich erkennen kann, dass Outlook vollständig initialisiert ist, denn ich glaube, genau da liegt der Fehler. Aber ein Sleep ist nicht wirklich prima, wegen den massiven Unterschieden in der Arbeitsgeschwindigkeit der Rechner ...

Re: Task für Automation ermitteln?

10. Dezember 2009 15:52

Bringt es was, das Create mit IF abzufangen?

Re: Task für Automation ermitteln?

10. Dezember 2009 16:01

Denke nicht - der Rückgabewert von CREATE sagt doch nur aus ob ein Objekt erstellt werden konnte und nicht, ob es fertig initialisiert ist (oder?). Ich habe das gerade mal eingebaut - die Fehlermeldung die ich bekomme ist

"Diese Meldung ist für C/AL-Programmierer:

Der Member CreateItem konnte nicht verarbeitet werden. Das OLE
Control gab eine unbekannte Meldung zurück"

Alternativ habe ich auch mit Sleep gerade experimentiert - auf diesem PC würde ein Wert von Sleep(5000) ausreichen ... es deutet also darauf hin dass ich zu früh das MailItem erstelle.

Re: Task für Automation ermitteln?

10. Dezember 2009 16:04

Ich meinte das Create(OApp). Wenn du hier schon einen Fehler bekommen hättest, wäre ja vielleicht eine Schleife gegangen, die das ein paar mal versucht, bis sie ein true erhält oder nach x erfolglosen Versuchen abbricht, aber das war dann ja wohl nix :roll: .

Re: Task für Automation ermitteln?

10. Dezember 2009 16:35

McClane hat geschrieben:Bringt es was, das Create mit IF abzufangen?


Stimmt, das könnte helfen,
und ich habe gelesen, das mit WSH eine Instanz eine Anwendung gestartet werden kann. Diese Instanz gibt nach dem Start einen Rückgabewert zurück
(Frag mich aber nicht wie, das müsstest du recherchieren)

Evtl. helfen dir diese Beiträge weiter (sind zwar VB-Script, aber schon dicht dran wenn ich mich nicht täusche!?):
supportnet.de - ob es möglich ist, mit vbscript oder wsh herauszubekommen, ob eine instanz eines bestimmten programms läuft?
spotlight.de - Prüfen ob Exe gestartet

Re: Task für Automation ermitteln?

11. Dezember 2009 10:39

So, ich denke ich hab das Paket zusammen.

Im Mopment haben wir uns so entschieden, dass wir ein gestartetes outlook 2007 vorraussetzen. Um das zu prüfen, haben wir eine Prüfung, wie in http://www.msdynamics.de/viewtopic.php?f=7&t=4964 beschrieben.

Der Rest sieht dann so aus:

Code:
SendAtachement(pFileName : Text[100];pPath : Text[100];pSubject : Text[250])
IF FILE.EXISTS(pPath + pFileName) THEN BEGIN
 
  //Sicherstellen dass Outlook gestartet ist
  IF NOT hFunc.WmiProcessRunning('','OUTLOOK.EXE') THEN
    ERROR('Outlook 2007 muss installiert und gestartet sein');

  IF ISCLEAR(oApp) THEN BEGIN
    IF CREATE(oApp) THEN BEGIN
      SLEEP(5000);
      oMailItem := oApp.CreateItem(0);  //Mailitem erstellen
      oMailItem.Attachments.Add(pPath+pFileName);
      oMailItem.Subject := pSubject;
      oMailItem.Recipients.Add('MyMail@MyDomain.de');
      oMailItem.Display;
    END;
  END;

END ELSE BEGIN
  //TODO Behandlung wenn die Datei nicht gefunden wurde
END;


Technisch würde ich daher sagen: Gelöst, nur die Feinheiten müssen noch ausgetüftelt werden (wie z.B. wenn Outlook noch nicht läuft, starten und abwarten, bis es Einsatzbereit ist; was mache ich, wenn das Dokument durch einen Fehler nicht erstellt wurde etc. :wink: ). Danke an alle!

Re: [Gelöst]Task für Automation ermitteln?

11. Dezember 2009 11:15

Ich weiß zwar nicht genau ob ich den Code recht verstanden habe, aber ist das nicht "doppelt-gemoppelt",
erst hFunc.WmiProcessRunning, wenn Ok, dann CREATE(oApp) (plus 5 Sekunden warten).

Outlook ist doch schon offen nach der Prüfung hFunc.WmiProcessRunning, oder?
Bzw. was macht oApp?

Re: [Gelöst]Task für Automation ermitteln?

14. Dezember 2009 11:15

Hallo Mikka,

oh - das SLEEP hab ich noch vergessen rauszunehmen :wink: - das hat in einem Test auf meinem PC die Funktion von Outlook sichergestellt, alls ich noch ohne die ProcessRunning-Prüfung gearbeitet habe.

Wenn ich die CREATE-Funktion richtig verstehe, übernimmt sie bei Automation-Variablen die Referenz einer bereits bestehenden Instanz, ausser es gibt keine Instanz oder aber ich setze als zweites Argument TRUE:

If NewServer is FALSE (the default), CREATE will try to reuse an already running instance of the automation server referenced by Automation before creating a new instance. If NewServer is TRUE, CREATE will always create a new instance of the automation server.

Da ich ja mit einer bestehenden Instanz von Outlook arbeiten will, verzichte ich auf das zweite Argument. Die hFunc.WmiProcessRunning soll ja den Anwender vor allem darauf aufmerksam machen, wenn er Outlook noch nicht gestartet hat. Theoretisch kann man auf die ProcessRunning-Prüfung auch verzichten, aber dann muss man einen entsprechenden Sleep-Befehl gemessen am langsamsten Rechner (und davon haben wir ein paar ^^) einbauen, um sicherzustellen, dass Outlook nach dem Create auch wirklich vollständig läuft - alles andere führt sonst zu einem Absturz der Funktion. Richtig zufrieden bin ich damit auch nicht, aber es ist eine funktionierende Alternative, und der ERROR war eine Vorgabe :-?

Dafür sehe ich gerade einen anderen "Fehler" - muss mal nachsehen ob oApp lokal deklariert ist, ansonsten funktioniert das nur einmal ^^ ...

Re: [Gelöst]Task für Automation ermitteln?

16. Dezember 2009 23:05

Es PDF-Drucker, die nach dem Erstellen der Datei Outlook oder eine andere Form des Versands ansprechen können. Im Falle von Outlook kann man es auch so einstellen, daß die Email nicht sofort rausgeschickt wird. Falls Outlook nicht geöffnet ist, wird ein Emailobjekt erstellt und steht dann beim nächsten Öffnen unter "Postausgang". Hier kann es der Benutzer dann wieder öffnen und bearbeiten. Erst beim Klicken auf Senden wird es auch wirklich rausgeschickt. Es muß also auch eine Möglichkeit geben, ohne daß Outlook geöffnet sein muß. Aber das ist sicherlich wie immer auch eine Frage des Aufwands...

Re: [Gelöst]Task für Automation ermitteln?

17. Dezember 2009 10:43

Aber dafür muss Outlook erst mal gestartet sein, damit ich ein MailItem-Objekt erstellen kann. Ich denke aber ich habe es jetzt gelöst (jedenfalls kommen nun keine Fehlermeldungen mehr und die Mail landet im Postausgang). Für die Prüfung, ob Outlook läuft, verwende ich wieder http://www.msdynamics.de/viewtopic.php?f=7&t=4964.

Hier ist nun der Code, der sich um das Absenden kümmert. Anscheinend wird die Prüfung, ob der Task läuft, erst gültig, wenn Outlook komplett gestartet ist, zumindest ist das mein Eindruck. Ich teste das die Tage noch auf einem der langsamen PC's, um sicherzugehen, dass nicht das SLEEP(200) ausreicht, sondern dass das Outlook-Objekt erst erscheint, wenn es vollstätndig geladen ist.

Code:

SendAtachement(pFileName : Text[100];pPath : Text[100];pSubject : Text[250])
IF FILE.EXISTS(pPath + pFileName) THEN BEGIN
 
  IF ISCLEAR(oApp) THEN
    CREATE(oApp);

  CounterL := 0;
  REPEAT
    SLEEP(200);
    CounterL := CounterL + 1;
  UNTIL (hFunc.WmiProcessRunning('','OUTLOOK.EXE')) OR (CounterL = 30);

  IF CounterL < 30 THEN BEGIN
    oMailItem := oApp.CreateItem(0);  //Mailitem erstellen
    oMailItem.Attachments.Add(pPath+pFileName);
    oMailItem.Subject := pSubject;
    oMailItem.Recipients.Add('myMail@myDomain.de');
    oMailItem.Display;
  END ELSE
    MESSAGE('Bitte starten Sie Outlook 2007 und führen dann die Funktion erneut aus');
END ELSE BEGIN
  //TODO Behandlung wenn die Datei nicht gefunden wurde
END;


Der CounterL ist sozusagen eine Notbremse, damit daraus kein endloser Ablauf wird. Die Empfängerbehandlung ist hier noch nicht drin, ich denke aber, dass man das mit einem Text-Array gut lösen kann :-) .
Zuletzt geändert von Natalie am 17. Dezember 2009 10:46, insgesamt 1-mal geändert.
Grund: Code-Tag richtig geschlossen

Re: [Gelöst]Task für Automation ermitteln?

18. Dezember 2009 16:34

CaddyM hat geschrieben:Aber dafür muss Outlook erst mal gestartet sein, damit ich ein MailItem-Objekt erstellen kann.

Das habe ich schon verstanden, daß das dein Problem ist. Ich wollte damit nur sagen, daß es PDF-Drucker gibt, die es auch können, ohne daß Outlook geöffnet ist. Vielleicht über einen anderen Weg, vielleicht mit einem anderen Objekt aus der Outlook-API, keine Ahnung... es geht jedenfalls irgendwie. Aber solange deine Lösung für deine Zwecke reicht, würde ich keine weitere Energie reinstecken. :-)