2015-09-02 5 views
9

जब सी # में एक फ़ोल्डर का नाम बदलने, System.IO.Directory.Move फेंकता System.IO.IOException (संदेश "पहुँच अस्वीकृत") यदि उस फ़ोल्डर या किसी सबफ़ोल्डर वर्तमान में एक (विंडोज 7) अन्वेषक द्वारा खोला जाता है खिड़की। कमांडलाइन RENAME का उपयोग करना भी विफल रहता है। दूसरी एक्सप्लोरर विंडो का उपयोग करना सफल होता है।C# जो वर्तमान में Windows Explorer द्वारा खोला जाता है में एक फ़ोल्डर का नाम बदलने के लिए

त्रुटि फ़ोल्डर (या उसके माता-पिता) को ध्वस्त करने के बाद भी त्रुटि बनी रहती है। वास्तव में विशेष एक्सप्लोरर विंडो बंद होने की जरूरत है। तो एक्सप्लोरर फ़ोल्डर संरचना को दिखाने के लिए कुछ ताले बनाने लगता है और वास्तविक फ़ोल्डर अब प्रदर्शित नहीं होने पर भी उन्हें जारी नहीं करता है (जो शुद्ध नॉनेंस आईएमओ है)।

क्या किसी फ़ोल्डर का नाम बदलने के लिए कोई तरीका है (प्रोग्राम में उदा। सी # का उपयोग करना), जो वर्तमान में प्रदर्शित होता है (या दिखाई देता है, उपरोक्त दिखाई देता है) एक एक्सप्लोरर विंडो द्वारा?

अद्यतन

मिले एक तरीके के रूप इस सवाल का मेरे अपने जवाब द्वारा वर्णित (नीचे देखें) SHFileOperation() का उपयोग कर। हालांकि, यह समाधान बहुत व्यवहार्य नहीं है (नीचे भी देखें)।

+0

मैंने इसका परीक्षण किया है और यह काम करता है, शायद आपके पास फ़ाइल भी खुली है या उस फ़ोल्डर के लिए पर्याप्त अनुमति नहीं है। मैंने एक डीआईआर 'डी: \ ए' बनाया है और एक्सप्लोरर के माध्यम से इसे ब्राउज किया है, जब मैंने इस कोड को निष्पादित किया है 'Directory.Move (" D: \\ a "," D: \\ b ");', फ़ोल्डर नाम एक्सप्लोरर और लोकेशन बार में स्वचालित रूप से बदल गया। –

+0

@ वाउटर: मुझे लगता है कि आपको एक और स्तर जोड़ने की जरूरत है। 'D: \ a \ b' बनाएं, एक्सप्लोरर के माध्यम से' D: \ a \ b' पर ब्राउज़ करें और फिर 'a' (' x' या जो भी हो) का नाम बदलने का प्रयास करें। यह यहाँ काम नहीं करता है। अब 'ए' या' कंप्यूटर 'पर ब्राउज़ करें, इसलिए उस विंडो में न तो' ए 'और न ही 'बी' दिखाए जाते हैं (केवल ड्राइव दिखाए जाते हैं)। यह अब भी काम नहीं करता है। बीटीडब्लू, कोई फाइल नहीं खुलती है और निश्चित रूप से कोई अनुमति नहीं है। – user2261015

+0

आंशिक रूप से, जब एक्सप्लोरर सबफ़ोल्डर दिखाता है, तो यह 'IOException' फेंकता है, जब एक्सप्लोरर रूट ड्राइव दिखाता है, यह काम करता है। मुझे कहना होगा कि मैं विंडोज 10 पर परीक्षण कर रहा हूं जो मामूली अंतर की व्याख्या कर सकता है। –

उत्तर

2

तो मैं कुछ आगे reasearch के बाद अपने ही सवाल का जवाब कर रहा हूँ ..

फ़ोल्डर के रूप में यहाँ दिखाया गया है SHFileOperation() का उपयोग कर नाम दिया जा सकता: https://msdn.microsoft.com/en-us/library/windows/desktop/bb776887%28v=vs.85%29.aspx (चाहे यह 'जादू' Wouter या नहीं द्वारा उल्लिखित का उपयोग करता है। ;-)

लेकिन यदि कोई विंडोज/नेट एपीआई है जैसे System.IO.Directory.Move, डब्ल्यूटीएफ मुझे शैल का उपयोग करने की ज़रूरत है? प्रदर्शन के बारे में बात नहीं कर रहा ...

वैसे भी, SHFileOperation() का उपयोग कर एक दर्द है .. सी # का उपयोग करके आपको यह सभी पी-इनवॉक सामग्री घोषित करने की आवश्यकता है। और इस विशेष मामले में आपको 32 और 64-बिट विंडो के लिए अलग-अलग structs का उपयोग करने की आवश्यकता है, क्योंकि पैकिंग अलग है (http://www.pinvoke.net/default.aspx/shell32.shfileoperation देखें)। यह बहुत बोझिल है, आमतौर पर मैं लक्ष्य के रूप में AnyCPU निर्दिष्ट करता हूं। इस बिंदु पर आपको या तो 64 या 32 बिट प्रक्रिया के आधार पर रनटाइम (वास्तव में बहुत बुरा) पर शाखा की आवश्यकता है, या आप दो अलग-अलग लक्ष्यों के लिए अलग-अलग निर्माण करते हैं, जो कि मूर्खतापूर्ण एक्सप्लोरर के आसपास काम करने के लिए काफी बड़ा प्रभाव है।

सम्मान

4

मैंने विंडोज एपीआई कॉल की निगरानी के लिए API Monitor v2 by Rohitab का उपयोग किया है।

जब D:\test से D:\abc लिए निर्देशिका का नाम बदलने, इस कॉल लॉग इन किया गया था:

enter image description here

आप के रूप में:

explorerframe.dll ITransferSource::RenameItem (0x0000000015165738, "abc", TSF_COPY_CREATION_TIME | TSF_COPY_LOCALIZED_NAME | TSF_COPY_WRITE_TIME | TSF_DELETE_RECYCLE_IF_POSSIBLE, 0x00000000150f77d0) 

पर नजर रखने के उत्पादन में आगे खुदाई कुछ देशी कॉल से पता चलता देख सकते हैं, वे MoveFile का उपयोग नहीं कर रहे हैं, इसके बजाय, वे NtOpenFileFILE_OPEN_FOR_BACKUP_INTENT और अन्य लोगों को मूल निर्देशिका खोलने के लिए उपयोग करते हैं, फिर कैल एल NtSetInformationFile नई निर्देशिका नाम और ध्वज FileRenameInformation के साथ जो here दस्तावेज है।

दुर्भाग्यवश, ये सभी कर्नेल कॉल हैं।

आप ++ इस तरह C/C एक निर्देशिका उपयोगकर्ता के मोड से करने के लिए एक संभाल प्राप्त कर सकते हैं:

HANDLE h = ::CreateFileA("D:\\test", 
    DELETE | FILE_READ_ATTRIBUTES | SYNCHRONIZE, 
    FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 
    OPEN_EXISTING, 
    FILE_FLAG_BACKUP_SEMANTICS, 
    NULL); 

लेकिन फिर भी, आप अभी भी NtSetInformationFile -call के लिए एक उपयोगकर्ता के मोड विकल्प की जरूरत है।

कुछ विकल्प आगे बढ़ने के लिए (जटिलता द्वारा आदेश दिया):

  • देखें आप उपयोगकर्ता के मोड समाधान में खोल इंटरफ़ेस ITransferSource::RenameItem का उपयोग करें या एक के लिए तैयार के लिए उपयोग खोल समारोह
  • खुदाई मिल सकता है आगे और NtSetInformationFile
  • एक ड्राइवर को लिखें जो एक IOCTL है जो इन कर्नेल-मोड सामग्री करता है और C# से DeviceIoControl पर कॉल करें।

अद्यतन

लगता SHFileOperation समारोह ऊपर के सभी के रूप में ओ पी द्वारा पाया करता है।

इस उत्तर को ऑनलाइन छोड़ देगा, क्योंकि यह दूसरों को समान समस्याएं डीबग करने और मूल्यवान पॉइंटर्स प्राप्त करने के तरीके दिखा सकता है।

0

मुझे एक ही समस्या थी। जैसे ही मेरे पास एक एक्सप्लोरर विंडो खुलती थी और एक बार नाम बदलने के लिए फ़ोल्डर में नेविगेट किया गया था, Directory.Move "पहुंच से वंचित" (विंडोज 7 व्यावसायिक 64 बिट, x86 के रूप में संकलित अनुप्रयोग) के साथ विफल रहा।

दिलचस्प बात यह है कि Microsoft.VisualBasic.FileIO.FileSystem.MoveDirectory(...) कमांड को एक नई निर्देशिका में स्थानांतरित करने के लिए सफल होता है, यह केवल पुरानी निर्देशिका को हटाने में विफल रहता है यदि आप स्थानांतरित करने के लिए निर्देशिका के उपफोल्डर के अंदर रह रहे हैं। यह पहली त्रुटि पर फेंक दिया गया अपवाद पकड़कर तय किया जा सकता है और दूसरी बार फिर से प्रयास करें। अब स्रोत फ़ोल्डर भी हटा दिया गया है।

संबंधित मुद्दे