(Erledigt) Code bei Selektion eines Debitor ausführen

7. Februar 2014 09:58

Guten Morgen liebe Gemeinde,

zum Anbinden einer DMS Software muss ich es schaffen, das unser NAV 2009 RTC bei der Selektion eines Debitor in der Page 22 (Debitorenübersicht) einen Code ausführt bei dem die gerade selektierte Debitorennummer mit übergeben wird.
Leider stehe ich gerade vollkommen auf dem Schlauch, wo ich den Code einfügen muss damit er sobald ich einen anderen Debitor in der Liste selektiere aufgerufen wird.
Kann mir hier jemand sagen wo der Code eingebunden werden muss, damit er beim Aufruf der Page und bei der Selektion eines Debitors in der Übersicht ausgeführt wird?

Gruß
Fuige
Zuletzt geändert von fuige am 14. Mai 2014 15:35, insgesamt 1-mal geändert.

Re: Code bei Selektion eines Debitor ausführen

7. Februar 2014 10:22

Hallo,

ich nehme mal an "selektieren" ist das Thema, oder? Oder geht es darum ein Control zu versorgen, um das aktuelle Record der Page zu kennen? Dann ists eigentlich OnAfterGetRecord().

LG Jens

Re: Code bei Selektion eines Debitor ausführen

7. Februar 2014 10:51

Hi!

Es geht darum, das bei Selektion eines Debitor in der Debitorenübersicht automatisch ein Aufruf mit Übergabe der Debitorennummer an die Schnittstellensoftware zum DMS übergeben wird.
Wird die Debitorenkarte geöffnet, so soll natürlich auch dann diese Information übergeben werden. Hier ist's sicherlich der OnAfterGetRecord.
Nur bei der Selektion innerhalb der Debitorenübersicht bin ich mir nicht klar wo der Aufruf hinterlegt werden muss.

Hoffe das hilft zum Verständnis.

Re: Code bei Selektion eines Debitor ausführen

7. Februar 2014 12:23

Hallo,

in NAV 2009 wirst du das nur im "OnAfterGetRecord" Trigger der Page hinkriegen.

Code:
CurrPage.SetSelectionFilter(myDebitorRecordVariable);
If myDebitorRecordVariable.findset then begin
........
end;


Schau mal, ob du damit zurecht kommst.
Klar musst du darauf achten, dass die Funktion nicht beim Öffnen der Liste bereits für jeden Debitor angestoßen wird automatisch.
Deswegen würde ich mit SetSelectionFilter arbeiten.


Gruß
Aydin

Re: Code bei Selektion eines Debitor ausführen

8. Februar 2014 13:36

Hi!

Ich werde es nun in den Übersichsseiten über FactBoxes lösen.
Leider habe nun aber das Problem, das ich noch nie den Aufruf einer externen EXE Datei eingebunden habe.

Setze ich im OnAfterGetRecord Trigger folgenden Code ein
Code:
"C:\ECM\TEST\Connect 3\Shell.exe"
"ObjectSwitch@@PAR:object=Kunde@@PAR:objectvalue="No.""


so erhalte ich die Meldung das
"C:\ECM\TEST\Connect 3\Shell.exe"
eine unbekannte Variable ist.

Wie muss ich den Aufruf der beiden Codezeilen im OnAfterGetRecord einbinden?

Re: Code bei Selektion eines Debitor ausführen

8. Februar 2014 14:07

Habe inzwischen etwas in dieser Art gefunden.
Hier meckert das System nun beim speichern einen Syntax Fehler an.

Code:
CREATE(WSHShell);
varDMS := '"ObjectSwitch@@PAR:object=Kunde@@PAR:objectvalue=' + "No." + '"'
WSHShell.Run('"C:\ECM\TEST\Connect 3\Shell.exe"', varDMS);
CLEAR(WSHShell);

Re: Code bei Selektion eines Debitor ausführen

8. Februar 2014 19:13

Inzwischen habe ich mir ein paar Codezeilen zusammengestellt die soweit ich's bis hierher beurteilen kann, nun funktionieren.
Die jetzt noch erscheinende Fehlermeldung liegt denke ich eher noch an der extern Software.
Gibt's irgendwelche Bedenken oder Anregungen zu meinem Code?
Danke für euer Feedback!

Code:
varDMS := '"C:\ECM\TEST\Connect 3\Shell.exe" "ObjectSwitch@@PAR:object=Kunde@@PAR:objectvalue=' + "No." + '"';
runModally := FALSE;
windowState := 1;
CREATE(WSHSHELL,FALSE,TRUE);
WSHSHELL.Run(varDMS,windowState,runModally);
MESSAGE(varDMS);
CLEAR(WSHSHELL);

Re: Code bei Selektion eines Debitor ausführen

10. Februar 2014 11:19

Guten Morgen!

Da beim öffnen der Debitoren Page der Trigger mehrfach ausgelöst wurde, habe ich den Code noch um varNr ergänzt.

Nun würde ich gerne noch vor dem Aufruf prüfen lassen ob ...\Shell.exe überhaupt läuft.
Ist es irgendwie möglich diese Prüfung vorher ausführen zu lassen und je nach Ergebnis den folgenden Code auszuführen oder nicht?

Code:
IF varNr <> "No." THEN BEGIN //Connect nur einmal pro DebitorNr ansteuern
  varDMS := '"C:\ECM\TEST\Connect 3\Shell.exe" "ObjectSwitch@@PAR:object=Kunde@@PAR:objectvalue=' +  "No." + '"';
  runModally := FALSE;
  windowState := 1;
  CREATE(WSHSHELL,FALSE,TRUE);
  WSHSHELL.Run(varDMS,windowState,runModally);
  //MESSAGE(varDMS);
  CLEAR(WSHSHELL);
END;
varNr := "No.";



Gruß
Fuige

Re: Code bei Selektion eines Debitor ausführen

10. Februar 2014 12:02

meinst du ungefähr das?
Code:
IF ISCLEAR(wshshell) THEN

Re: Code bei Selektion eines Debitor ausführen

13. Februar 2014 21:41

guck mal in Page 1 rein, da wird ein ein "OnAfterGetCurrRecord" nachgebildet, wo du dich besser einklinken solltest ....
hat nämlich den Vorteil daß du bei mehrfachen klicken auf ein und demselben Debitor nur einmal deine Parameter weitergibst ...

Re: Code bei Selektion eines Debitor ausführen

1. März 2014 12:00

Hi und Entschuldigung das ich mich erst heute nochmal melde.

Was ich bräuchte wäre die Möglichkeit zu prüfen ob
"C:\ECM\TEST\Connect 3\Shell.exe"
bereits läuft. Falls nicht, dann soll das DMS System erst gar nicht über WSHSHELL.Run
angetriggert werden.

Mit
IF ISCLEAR(wshshell) THEN
würde ich doch "nur" prüfen ob der SHELL Aufruf leer ist und nicht ob das aufzurufende Programm des DMS bereits läuft?


h-d.neuenfeldt,
ich finde einen OnAfterGetRecord aber leider nicht den OnAfterGetCurrRecord.



Gruß u. schönes Karnevals WE
Fuige

Re: Code bei Selektion eines Debitor ausführen

3. März 2014 13:09

fuige hat geschrieben:Was ich bräuchte wäre die Möglichkeit zu prüfen ob "C:\ECM\TEST\Connect 3\Shell.exe"bereits läuft

Womöglich hilft dir dieses Thema weiter: viewtopic.php?f=7&t=4964

Re: Code bei Selektion eines Debitor ausführen

7. März 2014 15:01

ich finde einen OnAfterGetRecord aber leider nicht den OnAfterGetCurrRecord.


Nachbildung sieht so aus :
im Trigger OnAfterGetRecord wird die Funktion OnAfterGetCurrRecord aufgerufen

diese Dunktion sieht dann so aus :
Code:
xRec := Rec;
UpdateSystemIndicator


ABER
ich überleg mir gerade, wass diese Funktion mit der eigentlichen Bedeutung von "OnAfterGetCurrRecord" zu tun hat ....

Re: Code bei Selektion eines Debitor ausführen

20. März 2014 16:42

Hallo zusammen,

ich habe nun anhand der Beschreibung des Links von McClane einmal die Funktion WmiProccessRunning
in der aufrufenden Page angelegt u. den Code eingefügt
Code:
//WmiProccessRunning(pHost : Text[30];pExefile : Text[100]) pRunning : Boolean
//----------------------------------------------------------------------------
  //# oWmiSWbemLocator   Automation   'Microsoft WMI Scripting V1.2 Library'.SWbemLocator
  //# oWmiSWbemServices   Automation   'Microsoft WMI Scripting V1.2 Library'.SWbemServices
  //# oWmiSWbemObjectSet   Automation   'Microsoft WMI Scripting V1.2 Library'.SWbemObjectSet
  //# lSelect   Text      250

  // WmiProccessRunning : läuft Programm (Task) ?

  IF pHost = '' THEN
    pHost := '.';

  IF ISCLEAR(oWmiSWbemLocator) THEN
    CREATE(oWmiSWbemLocator);

  oWmiSWbemServices := oWmiSWbemLocator.ConnectServer(pHost);

  lSelect := STRSUBSTNO ('select name, description from Win32_Process where name="%1"', pExefile)

  oWmiSWbemObjectSet := oWmiSWbemServices.ExecQuery(lSelect);

  IF (oWmiSWbemObjectSet.Count > 0) THEN
    pRunning := TRUE
  ELSE
    pRunning := FALSE;



Im OnAfterGetRecord habe ich den Aufruf der Funktion inkl. der EXE Datei hinterlegt.


Local angelegte Variablen
pHost Text 30
pExefile Text 100

Global angelegte Variablen
oWmiSWbemLocator Automation 'Microsoft WMI Scripting V1.2 Library'.SWbemLocator
oWmiSWbemServices Automation 'Microsoft WMI Scripting V1.2 Library'.SWbemServices
oWmiSWbemObjectSet Automation 'Microsoft WMI Scripting V1.2 Library'.SWbemObjectSet
lSelect Text 250



Leider erscheint beim speichern ein SYNTAX Fehler bei der Zeile
oWmiSWbemObjectSet := oWmiSWbemServices.ExecQuery(lSelect);


Kann mir hier evtl. jemand nochmal weiter helfen?
Vielen Dank!


Gruß
Fuige

Re: Code bei Selektion eines Debitor ausführen

20. März 2014 16:46

Sorry,

die lokalen Variablen pHost und PExefile sind natürlich Parameter der Funktion und keine Variablen.

Re: Code bei Selektion eines Debitor ausführen

28. März 2014 08:41

Guten Morgen zusammen!

Inzwischen habe ich den übernommenen Code etwas angepasst und er lässt sich nun auch ausführen.
Als Problem habe ich nun aber noch, das die Zählung (Count) immer 0 zurück gibt.
Der mit lSelect übergebene String ist aber soweit ich es sehe korrekt und der zu prüfende Prozess läuft auch mit dem angezeigten Namen im Taskmanager.

Hat hier evtl. jemand noch eine Idee was ich anpassen muss?

Vielen Dank und einen hoffentlich sonnigen Tag uns allen!
Fuige

Code:
//WmiProccessRunning(pHost : Text[30];pExefile : Text[100]) pRunning : Boolean
//----------------------------------------------------------------------------
  //# oWmiSWbemLocator   Automation   'Microsoft WMI Scripting V1.2 Library'.SWbemLocator
  //# oWmiSWbemServices   Automation   'Microsoft WMI Scripting V1.2 Library'.SWbemServices
  //# oWmiSWbemObjectSet   Automation   'Microsoft WMI Scripting V1.2 Library'.SWbemObjectSet
  //# lSelect   Text      250

  // WmiProccessRunning : läuft Programm (Task) ?

  IF pHost = '' THEN
    pHost := '.';

  IF ISCLEAR(oWmiSWbemLocator) THEN
    CREATE(oWmiSWbemLocator);

  oWmiSWbemServices := oWmiSWbemLocator.ConnectServer(pHost);

  //lSelect := STRSUBSTNO ('select name, description from Win32_Process where name="%1"', pExefile);
  lSelect := STRSUBSTNO ('select name from Win32_Process where name="%1"', pExefile);
 
  oWmiSWbemObjectSet := oWmiSWbemServices.ExecQuery(lSelect);
 
  IF (oWmiSWbemObjectSet.Count > 0) THEN
    pRunning := TRUE
  ELSE
    pRunning := FALSE;

message('%1', prunning);

Re: Code bei Selektion eines Debitor ausführen

3. April 2014 09:11

Soll das auf dem Client laufen? Dann müsstest du dem Create noch Parameter mitgeben.

Re: Code bei Selektion eines Debitor ausführen

7. April 2014 10:45

Hallo McClane,

das ganze läuft in der Terminalsitzung des User (Client).
Mir ist aber leider nicht klar, was ich beim CREATE übergeben muss.
Könntest Du mir evtl. sagen wie der Aufruf aussehen muss?

Gruß
Fuige

Re: Code bei Selektion eines Debitor ausführen

7. April 2014 10:52

Creates an Automation object.


[Ok :=] CREATE(Automation [,NewServer] [,OnClient])



Parameters
Automation
Type: Automation

A variable that has previously been declared.

NewServer
Type: Boolean

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.

OnClient
Type: Boolean

If OnClient is false (the default), then the Automation object is created on the Microsoft Dynamics NAV Server. If OnClient is true, then the Automation object is created on the client.

This parameter is only valid when you run the function on the RoleTailored client. On the Classic client, the Automation object is always created on the client.

Property Value/Return Value


also könnte es bei dir so aussehen:
Code:
 IF ISCLEAR(oWmiSWbemLocator) THEN
    CREATE(oWmiSWbemLocator,TRUE,TRUE);

Re: Code bei Selektion eines Debitor ausführen

8. April 2014 07:26

Guten Morgen!

Sweikelt, dein Hinweis war die Lösung für das vorher genannten Problem.
Nun stehe ich aber bereits wieder vor der nächsten Hürde.
Da wir alle auf einem Windows Terminalserver als Client arbeiten, gibt die Abfrage
Code:
oWmiSWbemObjectSet.Count
immer die Anzahl der gefundenen Prozesse ALLER Benutzer zurück.
Wie kann ich es realisieren, das nur meine Prozesse überprüft werden und die entsprechende Rückmeldung erfolgt?

Vielen Dank für Eure bisherige Unterstützung und einen schönen Tag euch allen!
Fuige

Re: Code bei Selektion eines Debitor ausführen

8. April 2014 15:03

Das könnte man mit einem VB-Script vielleicht lösen, da die Objekte in dem oWmiSWbemObjectSet eine Methode "getOwner" besitzen.

Re: Code bei Selektion eines Debitor ausführen

22. April 2014 11:26

Hallo McClane,

auf Deinen Hinweis hin, konnte ich folgendes an Code Zeilen finden.
Code:
strComputer = "." 
Set colProcesses = GetObject("winmgmts:" & _ 
   "{impersonationLevel=impersonate}!\\" & strComputer & _ 
   "\root\cimv2").ExecQuery("Select * from Win32_Process") 

 
For Each objProcess in colProcesses 

 
    Return = objProcess.GetOwner(strNameOfUser) 
    If Return <> 0 Then 
        Wscript.Echo "Could not get owner info for process " & _   
            objProcess.Name & VBNewLine _ 
            & "Error = " & Return 
    Else   
        Wscript.Echo "Process " _ 
            & objProcess.Name & " is owned by " _   
            & "\" & strNameOfUser & "." 
    End If 
Next


Leider gelingt es mir aber nicht aus diesem allgemein gehaltenen Beispiel eine Lösung für meinen Fall zu erstellen.
Es beginnt bereits damit, das ich nicht weiß, als was objProcess und colProcesses definiert werden müssen?

Gruß
Fuige

Re: Code bei Selektion eines Debitor ausführen

22. April 2014 11:47

Ich habe mir da mal vor Zeiten etwas zurechtgegooglet und -gebastelt (jemand, der sich damit auskennt, macht das sicher eleganter :roll: ).

lokale Variablen:
Code:
Name             DataType      Subtype    Length
BSTRConverter    Automation    
'Navision Attain Hash 1.0'.BSTRConverter    
ScriptControl    Automation    
'Microsoft Script Control 1.0'.ScriptControl    
txtCR            Text                     30
txtCode          Text                     1024


Code:
CountProcessByOwner(ProcessName : Text[150];ProcessOwner : Text[30]) RetVal : Integer

IF ProcessName 
= '' THEN
  EXIT
;

CREATE(ScriptControl,TRUE);
CREATE(BSTRConverter,TRUE);

ScriptControl.Language := 'VBScript';
ScriptControl.AddObject('BSTRConverter',BSTRConverter);
txtCR := ' ';
txtCR[1] := 13;

txtCode := 'strComputer = "."' + txtCR +
           'Set objWMIService = GetObject("winmgmts:" _' + txtCR +
           '& "{impersonationLevel=impersonate}!\\" _' + txtCR +
           '& strComputer & "\root\cimv2")' + txtCR +
           'Set colProcessList = objWMIService.ExecQuery _' + txtCR +
           STRSUBSTNO('("Select * from Win32_Process Where Name = ''%1''")',ProcessName) + txtCR +
           'For Each objProcess in colProcessList' + txtCR;
IF ProcessOwner <> '' THEN
  txtCode 
+= 'colProperties = objProcess.getowner(strOwner,strDomain)' + txtCR +
             STRSUBSTNO('If strOwner = "%1" then',ProcessOwner) + txtCR;
txtCode += 'i = i + 1' + txtCR;
IF ProcessOwner <> '' THEN
  txtCode 
+= 'End if' + txtCR;
txtCode += 'Next' txtCR +
           'BSTRConverter.AppendNextStringPortion(i)';

ScriptControl.ExecuteStatement(txtCode);

IF BSTRConverter.BSTR <> '' THEN
  EVALUATE
(RetVal,BSTRConverter.BSTR);

CLEAR(ScriptControl);
CLEAR(BSTRConverter);


Musst du mal testen, was auf deinem Terminal dabei heraus kommt.

Re: Code bei Selektion eines Debitor ausführen

14. Mai 2014 15:35

Auch wenn es lange Zeit gedauert hat, so ist nun durch die wie immer gute Hilfe hier im Forum, in diesem Falle besonders durch McClane und einen sehr hilfsbereiten Support Mitarbeiter
dessen Arbeitgeber ich hier wegen Werbung nicht nennen möchte eine wie ich finde passable Lösung entstanden.

Für alle die evtl. auch einmal vor dieser Herausforderung stehen, hier nun die Beschreibung.

Code Unit 1
Zuerst wird die CodeUnit 1 angepasst, damit bereits beim Start von Navision die Prüfung erfolgt ob der Prozess läuft.

neue globale Variablen in CU 1
WSHSHELL Automation 'Windows Script Host Object Model'.WshShell
varDMS Text 250
runModally Boolean
windowState Integer
varNr Text 11
oWmiSWbemLocator Automation 'Microsoft WMI Scripting V1.2 Library'.SWbemLocator
oWmiSWbemServices Automation 'Microsoft WMI Scripting V1.2 Library'.SWbemServices
oWmiSWbemObjectSet Automation 'Microsoft WMI Scripting V1.2 Library'.SWbemObjectSet
oWmiSWbemObject Automation 'Microsoft WMI Scripting V1.2 Library'.SWbemObject
lSelect Text 250
user Text 250
ausfuehren Boolean


Code in LOGINSTART() der CU 1
Code:
//>> Prüfen ob ProzessXYZ.exe läuft
ausfuehren := WmiProccessRunning('','ProzessXYZ.exe');
IF ausfuehren = TRUE THEN BEGIN
   UserSetup."DMS aktiv" := TRUE;
   UserSetup.MODIFY;
END ELSE BEGIN
   UserSetup."DMS aktiv" := FALSE;
   UserSetup.MODIFY;
END;
//<< Prüfen ob ProzessXYZ.exe läuft




Neue Funktion zum ermitteln in der CU 1
WmiProccessRunning(pHost : Text[30];pExefile : Text[100]) pRunning : Boolean

Code:
//>>Funktion zum ermitteln ob der beim Aufruf übergebene Prozess für den ausführenden Benutzer läuft
  IF pHost = '' THEN
    pHost := '.';

  IF ISCLEAR(oWmiSWbemLocator) THEN
    CREATE(oWmiSWbemLocator,TRUE,TRUE);

  oWmiSWbemServices := oWmiSWbemLocator.ConnectServer(pHost);
 
  lSelect := STRSUBSTNO ('select name from Win32_Process where name="%1"', pExefile);
 
  oWmiSWbemObjectSet := oWmiSWbemServices.ExecQuery(lSelect);
 
  FOR i := 0 TO oWmiSWbemObjectSet.Count-1 DO BEGIN
    oWmiSWbemObject := oWmiSWbemObjectSet.ItemIndex(i);
   
    owner := oWmiSWbemObject.ExecMethod_('GetOwner');

    properties := owner.Properties_;

    property := properties.Item('USER');
    user := FORMAT(property.Value);

    //property := properties.Item('DOMAIN');
    //domain := FORMAT(property.Value);
       
    IF user = USERID THEN myProcesses += 1;
  END;
 
  IF ((oWmiSWbemObjectSet.Count > 0) AND (myProcesses > 0)) THEN
    pRunning := TRUE
  ELSE
    pRunning := FALSE;
//<<Funktion zum ermitteln ob der beim Aufruf übergebene Prozess für den ausführenden Benutzer läuft



Die Tabelle 91 (User Setup) wurde um das Boolean Feld "DMS aktiv" erweitert und wird pro Benutzer mit dem Abfrageergebnis pro Navision Start gefüllt.


In meinem Falle erfolgt das Ansteuern des zuvor geprüften Prozesses über eigens angelegte Factboxes.
In diesem Beispiel eine FactBox der Kontakte.

neue globale Variablen in der Page
WSHSHELL Automation 'Windows Script Host Object Model'.WshShell
varDMS Text 250
runModally Boolean
windowState Integer
varNr Text 11
varUSERSETUP Record User Setup


Code im OnAfterGetRecord() der Page um das DMS anzusteuern
Code:
//>> Ansteuern des DMS Programm
varUSERSETUP.SETFILTER(varUSERSETUP."User ID", USERID);
varUSERSETUP.FINDFIRST;
IF varUSERSETUP."DMS aktiv" = TRUE THEN BEGIN //>>CU-1 hinterlegt "DMS aktiv" beim NAV Start in UserSetup
  IF varNr <> "No." THEN BEGIN //DMS nur einmal pro Kontakt beim Bewegen durch die Übersicht ansteuern
    //>> varDMS beinhaltet den Aufrufparameter zum ansteuern des DMS Programm pro Kontakt
    varDMS := '......';
   
    runModally := FALSE;
    windowState := 1;
    CREATE(WSHSHELL,FALSE,TRUE);
    WSHSHELL.Run(varDMS,windowState,runModally);
    CLEAR(WSHSHELL);
  END;
END;

varNr := "No.";
//<< Ansteuern des DMS Programm




Da wir auf einem Windows 2008 Terminalserver arbeiten benötigt die FOR Schleife in der Funktion einige Sekunden um den Prozess des entspr. Benutzers zu ermitteln.
Da dies zu im Alltag unbrauchbaren Verzögerungen innerhalb der Pages führt, habe ich mich für die Lösung innerhalb der CodeUnit 1 entschieden.

Ich hoffe diese Beschreibung ist dem ein oder anderen Hilfreich.
Sollte es Fragen, Anregungen oder Kritik geben so bin ich für jeden konstruktiven Beitrag dankbar.

Gruß und Dank an alle die mir dabei geholfen haben
Fuige