Eine Frage zu ShFileOperation



  • Hallo,

    Um allen Hinweisen zur Suchfunktion usw. vorzubeugen:
    Ich habe die Suche genutzt und auch zig Beiträge zu diesem Thema gefunden.
    Die haben mir jedoch alle nicht weitergeholfen.

    Folgendes Problem:

    Ich versuche, 1 (Eine) Datei zu kopieren bzw. verschieben (je nach Benutzerauswahl). Der Rückgabewert von ShFileOperation ist 0, jedoch wird die Datei weder kopiert noch verschoben.
    Der Quell-Ordner ist auf der lokalen Platte und der Zielordner ist ein verbundenes Netzlaufwerk.
    Das Resultat ist das gleiche, wenn ich den Zielordner normal angebe (mit Laufwerksbuchstabe) oder als UNC-Pfad.

    Folgender Quelltext:
    Aufruf der Funktion

    if (SumDialog->CheckBox1->Checked) {
    			if (SumDialog->co_mo->ItemIndex == 0) {
    				shFlag = FO_COPY;
    			}
    			else if (SumDialog->co_mo->ItemIndex == 1) {
    				shFlag = FO_MOVE;
    			}
    			ShowMessage("Rückgabewert von 'SHFileOperation()':  "+
    					IntToStr(ExecuteOp(resFileName, SumDialog->path->Text+ExtractFileName(resFileName), shFlag)));
    		}
    

    die Funktion

    int __fastcall TMainForm::ExecuteOp(AnsiString From , AnsiString  Dest, int IdOp)
    {
    	ShowMessage("From = "+From+"\nDest = "+Dest);
    
    	SHFILEOPSTRUCT ShFile;
    
    	ZeroMemory(&ShFile, sizeof(ShFile));
    
    	From += '\0';
    	Dest += '\0';
    
    	ShFile.hwnd   = NULL;
    	ShFile.wFunc = (UINT)IdOp;
    	ShFile.pFrom = From.c_str();
    	ShFile.pTo   = Dest.c_str();
    	ShFile.hNameMappings = NULL;
    	ShFile.lpszProgressTitle = NULL;
    
    //	if (IdOp != FO_DELETE)
    		ShFile.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_FILESONLY;
    //	else
    //		ShFile->fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION;
    
    	return (SHFileOperation(&ShFile));
    }
    

    Nach zwei Tagen probieren sehe ich wahrscheinlich den Wald vor lauter Bäumen nicht mehr???

    Gruß Udo



  • Hallo,

    Hast du dir das hier durchgelesen?
    http://msdn.microsoft.com/en-us/library/bb762164.aspx
    Hier steht, das auch 0 zurückgegeben wird, wenn die Operation abgebrochen wurde. dazu mußt du fAnyOperationsAborted auswerten.



  • @Braunstein

    Danke für den Hinweis.
    Der Wert von ShFile.fAnyOperationsAborted ist 1.
    Entspricht das folgendem Fehler?:

    ERRORONDEST 0x10000 An unspecified error occurred on the destination.
    

    Wenn ja, was kann ich daraus schließen????

    Gruß Udo



  • fAnyOperationsAborted ist ein BOOL. Das bedeutet 1 entspricht true.

    fAnyOperationsAborted
    When the function returns, this member contains TRUE if any file operations were aborted before they were completed; otherwise, FALSE. An operation can be manually aborted by the user through UI or it can be silently aborted by the system if the FOF_NOERRORUI or FOF_NOCONFIRMATION flags were set.



  • Ok, dann wurde die Operation also vom System abgebrochen.
    Und wie erfahre ich den Grund des Abbruches?

    Im Link zur MSDN steht, das man GetLastError() nicht auf den Rückgabewert dieser Funktion anwenden kann.

    Gruß Udo



  • Mach doch mal FOF_SILENT und FOF_NOCONFIRMATION weg. Vielleicht siehst du dann etwas mehr.



  • @Braunstein

    Wenn Du mit mehr sehen eventuelle Bildschirmausgaben meinst, Fehlanzeige.

    Ich habe aber festgestellt, das das Kopieren, Verschieben in einen lokalen Ordner funktioniert (was mir aber nichts nützt!).

    Gruß Udo



  • Wo willst du das File den hinkopieren?

    Vielleicht hast du einfach keine Rechte dazu?



  • Die entsprechenden Rechte sind vorhanden, denn das kopieren über den Explorer geht.

    Gruß Udo



  • Vielleicht ist ja doch ein Fehler im Pfad. Prüf doch, vor dem Verschieben, ob der Pfad korrekt ist. Dafür könntest Du DirectoryExists() verwenden.



  • @Joe_M

    DirectoryExists() liefert false, obwohl das Verzeichnis existiert und auch das Netzlaufwerk verbunden ist (Definitiv).

    Ich vermute jetzt, das die Ursache des Problems ganz woanders liegt, nämlich im Zusammenspiel zweier von mir geschriebener Programme.
    Ich versuche mal, den Ablauf zu erklären.

    Auf dem Rechner läuft ein Dienst, welcher in einem Thread einen bestimmten Ordner überwacht. Bei Eintreten eines definierten Ereignisses (erstellen einer Datei) wird eine Application gestartet (das ist die, in der die Probleme mit dem Netzwerkordner auftreten), welch mit der erstellten Datei bestimmte Aktionen ausführt.

    Hier ein Codeausschnitt des Dienstes:

    void __fastcall DcamThread::Execute()
    {
    	DWord dwBytesReturned;
    	char *cDir = GetRegValue(HKEY_CURRENT_USER,....);
    	String Msg, OldFName, NewFName;
    	bool IsValidFile;
    	dwBytesReturned = 0;
    
    	CreateDirHandle(cDir);
    	DWORD bufSize = sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH*sizeof(WCHAR);
    	while (!Terminated)
    	{
    		if (pHandle != INVALID_HANDLE_VALUE)
    		{
    			ZeroMemory(pWorkPtr, bufSize);
    			ReadDirectoryChangesW(pHandle,
    			&pWorkPtr, sizeof(pWorkPtr), false,
    //			FILE_NOTIFY_CHANGE_FILE_NAME &&
    			FILE_NOTIFY_CHANGE_LAST_WRITE //&&
    //			FILE_NOTIFY_CHANGE_DIR_NAME &&
    //			FILE_NOTIFY_CHANGE_ATTRIBUTES &&
    //			FILE_NOTIFY_CHANGE_LAST_ACCESS &&
    //			FILE_NOTIFY_CHANGE_CREATION
    			, &dwBytesReturned, NULL, NULL);
    			NewFName = "";
    			OldFName = "";
    			if (dwBytesReturned > 0)
    			{
    				switch(pWorkPtr->Action)
    				{
    					case FILE_ACTION_MODIFIED:
    						if (ExtractFileExt(AnsiString(pWorkPtr->FileName)).UpperCase()==".DOC" && IsValidFile) {
    							// erst wenn die zum aktuellen NC-Programm gehörende .doc-Datei erstellt bzw.
    							// geändert wird das Konvertierungsprogramm starten
    							FileAddAction(AnsiString("\""+(String)cDir+"\\"+
    											(String)pWorkPtr->FileName+"\"").c_str(),pWorkPtr->FileName);  //--> die relevante Aktion auf dem Laufwerk
    						}
    						else {
    							IsValidFile = (ExtractFileExt(AnsiString(pWorkPtr->FileName)).UpperCase()==".DR");
    						}
    						break;
    					case FILE_ACTION_REMOVED:
    						ShowMessage("Datei gelöscht:  "+(String)pWorkPtr->FileName);
    						break;
    					case FILE_ACTION_RENAMED_OLD_NAME: OldFName = (String)FILE_ACTION_RENAMED_OLD_NAME;break;
    					case FILE_ACTION_RENAMED_NEW_NAME: NewFName = (String)FILE_ACTION_RENAMED_NEW_NAME;break;
    				}
    				if (!OldFName.IsEmpty()) {
    					Msg = "Datei umbenannt von '"+OldFName+"' in '"+NewFName+"'";
    				}
    				dwBytesReturned = 0;
    			}
    		}
    	}
    	delete pWorkPtr;
    	delete pHandle;
    }
    //---------------------------------------------------------------------------
    
    void __fastcall DcamThread::FileAddAction(const char* ParamName, const wchar_t* FName)
    {
    	ExePath = AnsiString(GetRegValue(HKEY_LOCAL_MACHINE,....));
    	String FileExt = ExtractFileExt(FName);
    	ncName = AnsiString(ParamName);
    	ncName = ncName.SubString(1,ncName.Pos(FileExt))+"dr";
    	Synchronize(StartApplication((ExePath+"\\mitsu2sinumerik.exe").c_str(),ncName.c_str()));
    }
    //---------------------------------------------------------------------------
    

    Das ganze läuft wunderbar bis auf die Tatsache, das in der gestarteten Application scheinbar überhaupt keine Netzwerkressourcen zur Verfügung stehen.

    Kann sich das vielleicht mal einer von Euch Experten anschauen?

    Gruß Udo



  • Ich nochmal.

    Der Quelltextausschnitt aus dem vorigen Beitrag ist so:

    ...
    ...
    void __fastcall DcamThread::FileAddAction(const char* ParamName, const wchar_t* FName)
    {
    	ExePath = AnsiString(GetRegValue(HKEY_LOCAL_MACHINE,....));
    	String FileExt = ExtractFileExt(FName);
    	ncName = AnsiString(ParamName);
    	ncName = ncName.SubString(1,ncName.Pos(FileExt))+"dr";
    	StartApplication((ExePath+"\\mitsu2sinumerik.exe").c_str(),ncName.c_str());
    }
    

    Synchronize geht nicht mit Funktionen, welche Parameter übernehmen.

    Gruß Udo



  • Kommt das Programm (numerik.exe) denn mit Netzwerkressourcen klar, wenn es direkt aufgerufen wird, z.B. aus dem Explorer?



  • @Jansen
    Auf die Idee,das zu probieren bin ich noch garnicht gekommen.
    Werde das aber am Montag auf der Arbeit gleich testen und melde mich dann wieder.

    Gruß Udo



  • Hi,

    kann es nicht sein, daß es nicht reicht wenn Du die Rechte hast, vielleicht mußt Du sie außerdem noch an System vergeben. Daran hapert es zum Beisppiel manchmal wenn die Paradoxusrslock auf C:\ geschreiben werden soll und Du hast da alle Rechte und es geht trotzdem nicht.
    Nur mal so als möglicher Gedanke.

    Gruß Mümmel



  • @Jansen

    Ich habe jetzt das Programm von der Kommandozeile gestartet. Es sind alle Netzwerkressourcen vorhanden und das Kopieren/Verschieben in den Netzwerkordner funktioniert tadellos.

    Jetzt fällt mir auch wieder folgendes ein:
    Irgendwann während der Entwicklung ist mir mal aufgefallen, dass im normalen Druckerdialog alle Netzwerkdrucker fehlen. Ich habe mir aber damals keinen Kopf drüber gemacht, weil ich die im Programm sowieso nicht brauche. Aber das beruht wahrscheinlich auf der gleichen Ursache.

    hat jemand von Euch einen Hinweis, was ich jetzt machen kann???

    Gruß Udo



  • Hallo,

    ich habe jetzt mal den Start der Exe mit 'CreateProcess(...)' durchgeführt.
    ---> Das gleiche Verhalten wie vorher.

    Jetzt habe ich die Vermutung, das das an der Installation des Dienstes liegt, er läuft unter dem normalen Systemkonto.
    Wenn ich aber den Dienst unter meinem Konto laufen lasse, dann wird die Exe nicht gestartet (auch keine Fehlerausgabe).

    Gruß Udo



  • Hallo,

    Ich muß den Post nochmal nach oben bringen.
    Hat keiner eine Idee, was ich noch machen könnte???

    Gruß Udo



  • Hallo,

    Udo_11 schrieb:

    Jetzt habe ich die Vermutung, das das an der Installation des Dienstes liegt, er läuft unter dem normalen Systemkonto.

    Und was ist nun daraus geworden? Kannst du deine Vermutung inzwischen bestätigen / entkräften?

    Udo_11 schrieb:

    Wenn ich aber den Dienst unter meinem Konto laufen lasse, dann wird die Exe nicht gestartet (auch keine Fehlerausgabe).

    Das ist auch nicht das richtige Verhalten, oder?

    MfG



  • Hallo,

    wenn ein Dienst unter dem lokalen Systemkonto läuft, dann ist eine Interaktion mit dem Desktop möglich. --> Das Programm wird gestartet.

    läuft der Dienst jedoch unter einem beliebigen Benutzerkonto, dann ist eine Interaktion mit dem Desktop nicht mehr möglich. -->das Programm wird nicht gestartet.

    Ich nehme an, das ist das normale Verhalten eines Windowsdienstes.

    Die Frage ist, ob es normales Verhalten ist, das unter dem lokalen Systemkonto keine Netzwerkressourcen zur Verfügung stehen und ob bzw. wie ich das ändern kann.

    Gruß Udo


Log in to reply