আমি কীভাবে এক্সেল ইন্টারপ অবজেক্টগুলি সঠিকভাবে পরিষ্কার করব?


747

আমি সি # ( ApplicationClass) তে এক্সেল ইন্টারপ ব্যবহার করছি এবং নিম্নলিখিত কোডটি আমার শেষাংশে রেখেছি:

while (System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet) != 0) { }
excelSheet = null;
GC.Collect();
GC.WaitForPendingFinalizers();

যদিও এই ধরণের কাজ করে, Excel.exeআমি এক্সেল বন্ধ করার পরেও প্রক্রিয়াটি এখনও পটভূমিতে রয়েছে। আমার অ্যাপ্লিকেশনটি ম্যানুয়ালি বন্ধ হয়ে গেলে এটি কেবলমাত্র প্রকাশিত হয়।

আমি কী ভুল করছি, বা আন্তঃব্যবস্থাগুলি সঠিকভাবে নিষ্পত্তি করা হয়েছে তার কোনও বিকল্প আছে?


1
আপনি কি নিজের অ্যাপ্লিকেশনটি বন্ধ না করেই এক্সেল.সেক্সটি বন্ধ করার চেষ্টা করছেন? নিশ্চিত না যে আমি আপনার প্রশ্নটি পুরোপুরি বুঝতে পেরেছি।
ব্রায়ান্ট

3
আমি নিশ্চিত না করার চেষ্টা করছি যে ব্যবস্থাবিহীন আন্তঃব্যবস্থা সঠিকভাবে নিষ্পত্তি করা হয়েছে। যাতে আমরা যখন অ্যাপ্লিকেশন থেকে তৈরি করা এক্সেল স্প্রেডশিটটি ব্যবহারকারীর দ্বারা শেষ হয়ে যায় তখনও সেখানে এক্সেল প্রক্রিয়াগুলি ঘুরে না যায়।
এইডেস 17

3
আপনি যদি এক্সএমএল এক্সেল ফাইল তৈরি করে এটি চেষ্টা করতে পারেন, অন্যথায় দয়া করে ভিএসটিও আন / ম্যানেজড মেমোরি ম্যানেজমেন্টটি বিবেচনা করুন: jake.ginnivan.net/vsto-com-interop
জেরেমি থম্পসন

এটি কি এক্সেলে সুন্দরভাবে অনুবাদ করে?
Coops

2
মাইক্রোসফ্ট থেকে এই সমর্থন নিবন্ধটি দেখুন (নীচে উত্তরগুলি ছাড়াও), যেখানে তারা বিশেষত এই সমস্যার সমাধান দেয়: সমর্থন.microsoft.com/kb/317109
আরজান

উত্তর:


684

এক্সেলটি ছাড়েনি কারণ আপনার অ্যাপ্লিকেশনটি এখনও COM অবজেক্টের রেফারেন্স ধারণ করে।

আমার ধারণা আপনি কোনও COM অবজেক্টের কোনও ভেরিয়েবলকে বরাদ্দ না দিয়ে কমপক্ষে একজন সদস্যকে আহ্বান করছেন।

আমার জন্য এটি এক্সেল অ্যাপ্লিকেশন he ওয়ার্কশিটস অবজেক্ট যা আমি সরাসরি কোনও ভেরিয়েবলকে নির্ধারণ না করে ব্যবহার করেছি:

Worksheet sheet = excelApp.Worksheets.Open(...);
...
Marshal.ReleaseComObject(sheet);

আমি জানতাম না যে অভ্যন্তরীণভাবে সি # ওয়ার্কশিট COM অবজেক্টের জন্য একটি মোড়ক তৈরি করেছে যা আমার কোড দ্বারা প্রকাশিত হয়নি (কারণ আমি এটি সম্পর্কে অবগত ছিলাম না) এবং এটিই কেন এক্সেলটি লোড না করা হয়েছিল।

আমি এই পৃষ্ঠায় আমার সমস্যার সমাধান পেয়েছি , যা সি # তেও COM অবজেক্টের ব্যবহারের জন্য একটি দুর্দান্ত নিয়ম রয়েছে:

COM অবজেক্টস সহ কখনই দুটি বিন্দু ব্যবহার করবেন না।


সুতরাং এই জ্ঞানের সাথে উপরোক্ত কাজ করার সঠিক উপায়টি হ'ল:

Worksheets sheets = excelApp.Worksheets; // <-- The important part
Worksheet sheet = sheets.Open(...);
...
Marshal.ReleaseComObject(sheets);
Marshal.ReleaseComObject(sheet);

পোস্ট মর্টেম আপডেট:

আমি চাই যে প্রতিটি পাঠক হ্যানস প্যাস্যান্টের এই উত্তরটি খুব মনোযোগ সহকারে পড়ুন কারণ এতে আমি এবং অন্যান্য প্রচুর বিকাশকারী আটকা পড়েছিল explains বছরখানেক আগে আমি যখন এই উত্তরটি লিখেছিলাম তখন আমি জেনে নেই যে ডিবাগারটি আবর্জনা সংগ্রাহকের উপর কী প্রভাব ফেলে এবং ভুল সিদ্ধান্তে পৌঁছেছে। আমি আমার উত্তরটি ইতিহাসের জন্য নিরবচ্ছিন্ন রাখি তবে অনুগ্রহ করে এই লিঙ্কটি পড়ুন এবং "দুটি বিন্দু" এর পথে যাবেন না : নেট থেকে আবর্জনা সংগ্রহ বোঝা এবং আইডিসপোজেবলের সাহায্যে এক্সেল ইন্টারপ আইটেমগুলি পরিষ্কার করুন


16
তারপরে আমি সিওএম থেকে এক্সেল ব্যবহার না করার এবং সমস্ত সমস্যার নিজেকে বাঁচানোর পরামর্শ দিচ্ছি। এক্সেল 2007 ফর্ম্যাটগুলি কখনও এক্সেল খোলার ছাড়াই ব্যবহার করা যেতে পারে, টকটকে।
user7116

5
"দুটি বিন্দু" বলতে কী বোঝায় তা বুঝতে পারি নি। আপনি দয়া করে ব্যাখ্যা করতে পারেন?
এস 6

22
এর অর্থ, আপনি comObject.Property.PropertiesProperty প্যাটার্নটি ব্যবহার করবেন না (আপনি দুটি বিন্দু দেখতে পাচ্ছেন?) পরিবর্তে comObject.Poperty একটি ভেরিয়েবল বরাদ্দ করুন এবং ব্যবহার এবং সেই পরিবর্তনশীল নিষ্পত্তি। উপরোক্ত নিয়মের আরও একটি আনুষ্ঠানিক সংস্করণ হতে পারে h "আপনি ভেরিয়েবলগুলি ব্যবহারের আগে কম অবজেক্টকে বরাদ্দ করুন com এটিতে কম আইটেম অন্তর্ভুক্ত রয়েছে যা অন্য কম বস্তুর বৈশিষ্ট্য" "
ভিভিএস

5
@ নিক: আসলে, আপনার কোনও ধরণের পরিষ্কারের দরকার নেই, কারণ আবর্জনা সংগ্রহকারী আপনার পক্ষে এটি করবে। আপনার কেবলমাত্র যা করতে হবে তা হ'ল প্রতিটি COM অবজেক্টকে তার নিজস্ব ভেরিয়েবলের জন্য বরাদ্দ করা যাতে জিসি এটি জানতে পারে।
ভিভিএস

12
@ ভিএসএস বলটকে থামিয়ে দেয়, জিপি সমস্ত কিছুই পরিষ্কার করে দেয় যেহেতু মোড়ক ভেরিয়েবলগুলি নেট ফ্রেমওয়ার্ক দ্বারা তৈরি করা হয়। জিসি এটি পরিষ্কার করতে কেবল চিরকালের জন্য সময় নিতে পারে। ভারী ইন্টারপ পরে জিসি.কলেক্ট কল করা কোনও খারাপ আদর্শ নয়।
কোডিংবার্ডফিল্ড

280

আপনি প্রকৃতপক্ষে আপনার এক্সেল অ্যাপ্লিকেশন অবজেক্টটি প্রকাশ করতে পারেন তবে আপনাকে যত্ন নিতে হবে।

আপনার অ্যাক্সেসের প্রতিটি COM অবজেক্টের জন্য নামকরণের রেফারেন্স বজায় রাখা এবং তারপরে স্পষ্টভাবে এটি প্রকাশের পরামর্শটি Marshal.FinalReleaseComObject()তাত্ত্বিকভাবে সঠিক, তবে দুর্ভাগ্যক্রমে, বাস্তবে পরিচালনা করা খুব কঠিন। যদি কেউ যে কোনও জায়গায় পিছলে যায় এবং "দুটি বিন্দু" ব্যবহার করে, বা একটি for eachলুপ বা অন্য কোনও অনুরূপ কমান্ডের মাধ্যমে সেলগুলি পুনরাবৃত্তি করে , তবে আপনার কাছে অবাস্তব COM অবজেক্ট থাকবে এবং ঝুলন্ত ঝুঁকির ঝুঁকি থাকবে। এই ক্ষেত্রে, কোডটিতে কারণ খুঁজে পাওয়ার কোনও উপায় থাকবে না; আপনাকে চোখের দ্বারা আপনার সমস্ত কোড পর্যালোচনা করতে হবে এবং আশা করি কারণটি খুঁজে বের করতে হবে, এমন একটি কাজ যা কোনও বৃহত প্রকল্পের জন্য প্রায় অসম্ভব হতে পারে।

সুসংবাদটি হ'ল আপনার ব্যবহার করা প্রতিটি সিওএম অবজেক্টের জন্য আপনাকে আসলে একটি নামযুক্ত পরিবর্তনশীল রেফারেন্স বজায় রাখতে হবে না। পরিবর্তে, কল করুন GC.Collect()এবং তারপরে GC.WaitForPendingFinalizers()আপনি যে সমস্ত (সাধারণত গৌণ) অবজেক্টে রেফারেন্স রাখেন না তা ছাড়ুন এবং তারপরে স্পষ্টভাবে প্রকাশিত করুন এমন অবজেক্টগুলিতে যা আপনার নাম পরিবর্তনশীল রেফারেন্স ধারণ করে।

বিপরীত ক্রমের ক্ষেত্রে আপনার নামকৃত রেফারেন্সগুলিও প্রকাশ করা উচিত: প্রথমে পরিসীমা অবজেক্টস, তারপরে ওয়ার্কশিট, ওয়ার্কবুক এবং তারপরে আপনার এক্সেল অ্যাপ্লিকেশন অবজেক্টটি।

উদাহরণস্বরূপ, ধরে নিই যে আপনার একটি রেঞ্জ অবজেক্ট ভেরিয়েবল রয়েছে xlRng, একটি ওয়ার্কশিট ভেরিয়েবল নামক xlSheet, একটি ওয়ার্কবুক ভেরিয়েবল xlBookএবং একটি এক্সেল অ্যাপ্লিকেশন ভেরিয়েবল নাম রয়েছে xlApp, তবে আপনার ক্লিনআপ কোডটি নীচের মতো দেখতে পারে:

// Cleanup
GC.Collect();
GC.WaitForPendingFinalizers();

Marshal.FinalReleaseComObject(xlRng);
Marshal.FinalReleaseComObject(xlSheet);

xlBook.Close(Type.Missing, Type.Missing, Type.Missing);
Marshal.FinalReleaseComObject(xlBook);

xlApp.Quit();
Marshal.FinalReleaseComObject(xlApp);

সবচেয়ে কোড উদাহরণ আপনি পরিষ্কার আপ এর COM বস্তু .NET থেকে, জন্য দেখতে পাবেন GC.Collect()এবং GC.WaitForPendingFinalizers()কল দুইবার হিসাবে করা হয়েছে:

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();

তবে এটির প্রয়োজন হবে না, যদি না আপনি ভিজ্যুয়াল স্টুডিও সরঞ্জামগুলির জন্য অফিস (ভিএসটিও) ব্যবহার না করেন, যা চূড়ান্তকরণের ব্যবহার করে যা চূড়ান্তকরণের সারিতে প্রচারিত সামগ্রীর সামগ্রিক গ্রাফের কারণ করে। এই জাতীয় জিনিসগুলি পরবর্তী আবর্জনা সংগ্রহ না করা অবধি মুক্তি দেওয়া হবে না । তবে, আপনি যদি ভিএসটিও ব্যবহার না করে থাকেন তবে আপনার কল করা উচিত GC.Collect()এবং GC.WaitForPendingFinalizers()কেবল একবার।

আমি জানি যে স্পষ্টভাবে কল GC.Collect()করা একটি হ'ল না (এবং এটি অবশ্যই দু'বার করা খুব বেদনাদায়ক মনে হয়), তবে সত্যি কথা বলতে এর চারপাশের কোনও উপায় নেই। সাধারণ ক্রিয়াকলাপের মাধ্যমে আপনি এমন গোপন অবজেক্ট তৈরি করতে পারবেন যার কাছে আপনি কোনও রেফারেন্স রাখেন না তাই আপনি কল করা ছাড়া অন্য কোনও মাধ্যমে মুক্তি দিতে পারবেন না GC.Collect()

এটি একটি জটিল বিষয়, তবে এটি যা আছে তা আসলে এটি। একবার আপনি আপনার ক্লিনআপ পদ্ধতির জন্য এই টেমপ্লেটটি স্থাপন করলে আপনি সাধারণত মোড়কের প্রয়োজন ছাড়াই কোড করতে পারেন ইত্যাদি :-)

আমার এখানে একটি টিউটোরিয়াল আছে:

ভিবি.নেট / সিওএম ইন্টারপ দিয়ে অফিস প্রোগ্রামগুলি স্বয়ংক্রিয় করা

এটি ভিবি.এনইটি-র জন্য লেখা হয়েছে, তবে সেগুলি বন্ধ করে দেওয়া হবে না, সি # ব্যবহার করার সময় নীতিগুলি হুবহু একই।


3
সম্পর্কিত আলোচনা এক্সট্রিমভিটিটালক। নেট অফিস অটোমেশন ফোরামটিতে এখানে পাওয়া যাবে: xtremevbtalk.com/showthread.php?t=303928
মাইক রোজেনব্লুম

2
: যদি অন্য সমস্ত ব্যর্থ হয়, তারপর Process.Kill () (ক শেষ অবলম্বন হিসেবে) ব্যবহার করা যেতে পারে এখানে বর্ণনা অনুযায়ী stackoverflow.com/questions/51462/...
মাইক Rosenblum

1
আনন্দিত এটি রিচার্ড কাজ করে। :-) এবং এখানে একটি সূক্ষ্ম উদাহরণ যেখানে কেবল "দুটি বিন্দু" এড়ানো কোনও সমস্যা রোধ করার পক্ষে যথেষ্ট নয়: স্ট্যাকওভারফ্লো
মাইক রোজেনব্লাম

এখানে বিষয়ে মাইক্রোসফট মিশা Shneerson থেকে এই একটি মতামত 7 অক্টোবর, 2010 (এর, মন্তব্য তারিখ মধ্যে blogs.msdn.com/b/csharpfaq/archive/2010/09/28/... )
মাইক Rosenblum

আমি আশা করছি এটি আমাদের যে অবিরাম সমস্যায় ভুগছে তা সহায়তা করে। একটি অবরুদ্ধ ব্লকের মধ্যে আবর্জনা সংগ্রহ এবং কলগুলি ছেড়ে দেওয়া কি নিরাপদ?
ব্রেট গ্রিন

213

উপস্থাপনা: আমার উত্তরে দুটি সমাধান রয়েছে, সুতরাং পড়ার সময় সতর্ক থাকুন এবং কোনও কিছুই মিস করবেন না।

কীভাবে এক্সেল উদাহরণ আনলোড করা যায় তার বিভিন্ন উপায় এবং পরামর্শ রয়েছে যেমন:

  • মার্শালের সাথে স্পষ্টভাবে প্রতিটি কম অবজেক্ট প্রকাশ করা F ফিনালআরেলিজ কমঅবজেক্ট () (স্পষ্টভাবে তৈরি কম-অবজেক্টগুলি সম্পর্কে ভুলে যাবেন না)। প্রতিটি নির্মিত কম কম অবজেক্ট প্রকাশ করার জন্য, আপনি এখানে উল্লিখিত 2 টি বিন্দুর বিধি ব্যবহার করতে পারেন:
    আমি কীভাবে এক্সেল ইন্টারপ অবজেক্টগুলি সঠিকভাবে পরিষ্কার করব?

  • সিএলআর রিলিজকে অব্যবহৃত কম-অবজেক্টগুলি তৈরি করার জন্য জিসি.কলেক্ট () এবং জিসি.ওয়েটফরপেন্ডিং ফিনালাইজারস () কে কল করা হচ্ছে (আসলে এটি কাজ করে, বিশদের জন্য আমার দ্বিতীয় সমাধান দেখুন)

  • কম-সার্ভার-অ্যাপ্লিকেশনটি সম্ভবত কোনও উত্তর দেওয়ার অপেক্ষায় একটি বার্তা বাক্স দেখায় কিনা তা পরীক্ষা করা (যদিও আমি নিশ্চিত নই যে এটি এক্সেলটি বন্ধ হতে বাধা দিতে পারে তবে আমি এটি সম্পর্কে কয়েকবার শুনেছি)

  • মূল এক্সেল উইন্ডোতে WM_CLOSE বার্তা প্রেরণ

  • এক্সেলের সাথে পৃথক অ্যাপডোমায়নে কাজ করে এমন ক্রিয়াকলাপ সম্পাদন করা হচ্ছে। কিছু লোক বিশ্বাস করে যে অ্যাপ্লোমেনটি লোড করা হলে এক্সেল উদাহরণটি বন্ধ হয়ে যাবে।

  • আমাদের এক্সেল-আন্তঃবিদ্যুত কোডটি শুরুর পরে তাত্ক্ষণিকভাবে কার্যকর হওয়া সমস্ত এক্সেল দৃষ্টান্ত হত্যা করা।

কিন্ত! কখনও কখনও এই সমস্ত বিকল্পগুলি কেবল সহায়তা করে না বা উপযুক্ত হতে পারে না!

উদাহরণস্বরূপ, গতকাল আমি জানতে পেরেছিলাম যে আমার একটি ফাংশনে (যা এক্সেলের সাথে কাজ করে) এক্সেলটি ফাংশন শেষ হওয়ার পরে চলতে থাকে। আমি সব চেষ্টা করেছিলাম! আমি পুরো ফাংশনটি 10 ​​বার পুঙ্খানুপুঙ্খভাবে পরীক্ষা করে দেখেছি এবং মার্শাল.ফিনাল রিলিজকোমজেক্ট () সব কিছুর জন্য যুক্ত করেছি! আমারও ছিল জিসি.ক্লোকটেক্ট () এবং জিসি.ওয়েটফোরপেন্ডিং ফিনালাইজারস ()। আমি লুকানো বার্তার বাক্সগুলি পরীক্ষা করেছিলাম। আমি ডাব্লুএম_সিএলএসই বার্তাটি প্রধান এক্সেল উইন্ডোতে প্রেরণ করার চেষ্টা করেছি। আমি আমার ফাংশনটি একটি পৃথক অ্যাপডোমেনে সম্পাদন করেছি এবং সেই ডোমেনটি লোড করেছি। কিছুই সাহায্য করেনি! সমস্ত এক্সেল দৃষ্টান্ত বন্ধ করার বিকল্পটি অনুপযুক্ত, কারণ যদি ব্যবহারকারী আমার অন্য ক্রিয়াকলাপটি ম্যানুয়ালি শুরু করে, যখন আমার ক্রিয়াকলাপটি এক্সেলের সাথেও কাজ করে, তারপরে সেই উদাহরণটিও আমার ফাংশন দ্বারা বন্ধ হয়ে যাবে। আমি বাজি ধরছি ব্যবহারকারী খুশি হবে না! সুতরাং, সত্যি বলতে, এটি একটি খোঁড়া বিকল্প (কোনও অপরাধের লোক নয়)।সমাধান : এর মূল উইন্ডোটির hWnd দ্বারা এক্সেল প্রক্রিয়াটি হত্যা করুন (এটি প্রথম সমাধান)।

এখানে সহজ কোডটি রয়েছে:

[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

/// <summary> Tries to find and kill process by hWnd to the main window of the process.</summary>
/// <param name="hWnd">Handle to the main window of the process.</param>
/// <returns>True if process was found and killed. False if process was not found by hWnd or if it could not be killed.</returns>
public static bool TryKillProcessByMainWindowHwnd(int hWnd)
{
    uint processID;
    GetWindowThreadProcessId((IntPtr)hWnd, out processID);
    if(processID == 0) return false;
    try
    {
        Process.GetProcessById((int)processID).Kill();
    }
    catch (ArgumentException)
    {
        return false;
    }
    catch (Win32Exception)
    {
        return false;
    }
    catch (NotSupportedException)
    {
        return false;
    }
    catch (InvalidOperationException)
    {
        return false;
    }
    return true;
}

/// <summary> Finds and kills process by hWnd to the main window of the process.</summary>
/// <param name="hWnd">Handle to the main window of the process.</param>
/// <exception cref="ArgumentException">
/// Thrown when process is not found by the hWnd parameter (the process is not running). 
/// The identifier of the process might be expired.
/// </exception>
/// <exception cref="Win32Exception">See Process.Kill() exceptions documentation.</exception>
/// <exception cref="NotSupportedException">See Process.Kill() exceptions documentation.</exception>
/// <exception cref="InvalidOperationException">See Process.Kill() exceptions documentation.</exception>
public static void KillProcessByMainWindowHwnd(int hWnd)
{
    uint processID;
    GetWindowThreadProcessId((IntPtr)hWnd, out processID);
    if (processID == 0)
        throw new ArgumentException("Process has not been found by the given main window handle.", "hWnd");
    Process.GetProcessById((int)processID).Kill();
}

আপনি দেখতে পাচ্ছেন যে ট্রায় পার্স-প্যাটার্ন অনুসারে আমি দুটি পদ্ধতি সরবরাহ করেছি (আমি মনে করি এটি এখানে যথাযথ): প্রক্রিয়াটি হত্যা না করতে পারলে একটি পদ্ধতি ব্যতিক্রম ঘটায় না (উদাহরণস্বরূপ প্রক্রিয়াটির আর অস্তিত্ব নেই) , এবং অন্য পদ্ধতিটি যদি ব্যর্থ হয় তবে প্রক্রিয়াটি হত্যা না করা হয়। এই কোডের একমাত্র দুর্বল জায়গা হ'ল সুরক্ষা অনুমতি। তাত্ত্বিকভাবে, ব্যবহারকারীর প্রক্রিয়াটি মারার অনুমতি নাও থাকতে পারে, তবে সব ক্ষেত্রে 99.99% এ ব্যবহারকারীর কাছে এই জাতীয় অনুমতি রয়েছে। আমি এটি একটি অতিথি অ্যাকাউন্টের সাথেও পরীক্ষা করেছি - এটি পুরোপুরি কার্যকর করে works

সুতরাং, আপনার কোড, এক্সেলের সাথে কাজ করা, এটি দেখতে দেখতে দেখতে পারে:

int hWnd = xl.Application.Hwnd;
// ...
// here we try to close Excel as usual, with xl.Quit(),
// Marshal.FinalReleaseComObject(xl) and so on
// ...
TryKillProcessByMainWindowHwnd(hWnd);

ভাল খবর! এক্সেল সমাপ্ত! :)

ঠিক আছে, আসুন দ্বিতীয় সমাধানটিতে ফিরে যাই, যেমন আমি পোস্টের শুরুতে প্রতিশ্রুতি দিয়েছিলাম। দ্বিতীয় সমাধানটি হ'ল জিসি.কলেক্ট্রেট () এবং জিসি.ওয়েটফোরপেন্ডিংফাইনালাইজার ()। হ্যাঁ, এগুলি আসলে কাজ করে তবে আপনার এখানে যত্নবান হওয়া দরকার!
অনেক লোক বলে (এবং আমি বলেছি) যে সিসি কলেক্ট () কল করে কোনও লাভ হয় না। তবে এটি সাহায্য না করার কারণটি যদি এখনও COM অবজেক্টের উল্লেখ থাকে! জিসি.কলেক্ট () সহায়ক না হওয়ার অন্যতম জনপ্রিয় কারণ হ'ল প্রকল্পটি ডিবাগ-মোডে চালানো। ডিবাগ-মোড অবজেক্টগুলিতে যা প্রকৃতপক্ষে রেফারেন্স হয় না সেগুলি পদ্ধতিটির শেষ না হওয়া অবধি আবর্জনা সংগ্রহ করা হবে না।
সুতরাং, আপনি যদি জিসি.কলেক্টর () এবং জিসি.ওয়েটফরপেন্ডিংফাইনালাইজারস () চেষ্টা করে থাকেন এবং এটি কোনও উপকার না করে, তবে নিম্নলিখিতগুলি করার চেষ্টা করুন:

1) আপনার প্রকল্পটি রিলিজ মোডে চালানোর চেষ্টা করুন এবং এক্সেলটি সঠিকভাবে বন্ধ হয়েছে কিনা তা দেখুন

2) এক্সেলের সাথে কাজ করার পদ্ধতিটি একটি পৃথক পদ্ধতিতে মোড়ানো। সুতরাং এর পরিবর্তে এই জাতীয় কিছু:

void GenerateWorkbook(...)
{
  ApplicationClass xl;
  Workbook xlWB;
  try
  {
    xl = ...
    xlWB = xl.Workbooks.Add(...);
    ...
  }
  finally
  {
    ...
    Marshal.ReleaseComObject(xlWB)
    ...
    GC.Collect();
    GC.WaitForPendingFinalizers();
  }
}

তুমি লেখ:

void GenerateWorkbook(...)
{
  try
  {
    GenerateWorkbookInternal(...);
  }
  finally
  {
    GC.Collect();
    GC.WaitForPendingFinalizers();
  }
}

private void GenerateWorkbookInternal(...)
{
  ApplicationClass xl;
  Workbook xlWB;
  try
  {
    xl = ...
    xlWB = xl.Workbooks.Add(...);
    ...
  }
  finally
  {
    ...
    Marshal.ReleaseComObject(xlWB)
    ...
  }
}

এখন, এক্সেল বন্ধ হবে =)


19
দুঃখের বিষয় যে থ্রেডটি ইতিমধ্যে এত পুরানো যে আপনার দুর্দান্ত উত্তরটি নীচে থেকে উপস্থিত হয়েছে, যা আমি মনে করি এটি আরও বেশি বার
উত্সাহিত

15
আমাকে স্বীকার করতে হবে, যখন আমি আপনার উত্তরটি প্রথম পড়ি, তখন আমি ভেবেছিলাম এটি একটি বিশাল কলডেজ। প্রায় 6 ঘন্টা এর সাথে কুস্তি করার পরে (সবকিছু প্রকাশিত হয়েছে, আমার কাছে কোনও ডাবল ডট ইত্যাদি নেই got ইত্যাদি), এখন আমি মনে করি আপনার উত্তর প্রতিভা।
চিহ্নিত করুন

3
এর জন্য ধন্যবাদ. এমন এক্সেলের সাথে কুস্তি হয়ে গেছে যা এটি খুঁজে পাওয়ার আগে কয়েক দিন ধরেই বন্ধ হয় না। চমৎকার।
বিবিলেক

2
@ নাইটকোডার: দুর্দান্ত উত্তর, সত্যই বিস্তারিত। ডিবাগ মোড সম্পর্কিত আপনার মন্তব্যগুলি সত্য এবং গুরুত্বপূর্ণ যে আপনি এটি উল্লেখ করেছেন। রিলিজ মোডে একই কোডটি প্রায়শই ভাল হতে পারে। প্রক্রিয়া.কিলটি কেবলমাত্র অটোমেশন ব্যবহার করার সময়ই ভাল, যখন আপনার প্রোগ্রামটি এক্সেলের মধ্যে চলছে যেমন, যেমন, পরিচালিত সিওএম অ্যাড-ইন হিসাবে।
মাইক রোজেনব্লুম

2
@ ড্যানএম: আপনার পদ্ধতিটি 100% সঠিক এবং কখনই ব্যর্থ হবে না। আপনার সমস্ত ভেরিয়েবলগুলি পদ্ধতিতে স্থানীয় রাখার দ্বারা, সমস্ত রেফারেন্সগুলি NET কোড দ্বারা কার্যকরভাবে অ্যাক্সেসযোগ্য। এই মানে যখন আপনার পরিশেষে অধ্যায় আহ্বান GC.Collect (), জন্য finalizers যে সব আপনার এর COM বস্তু নিশ্চিতভাবে বলা হবে। প্রতিটি চূড়ান্তকরণকারী তখন মার্শালকে কল করে the আপনার পদ্ধতি তাই সহজ এবং বোকা-প্রমাণ। এটি ব্যবহার করে কোনও ভয় নেই। (কেবলমাত্র সতর্কীকরণ: যদি ভিএসটিও ব্যবহার করে তবে আমি সন্দেহ করি যে আপনিই, আপনার জিসি কলেক্ট () এবং জিসি.ওয়েটফোরপেন্ডিং ফিনালাইজারসকে দুটি কল করতে হবে))
মাইক রোজেনব্লাম

49

আপডেট : সি # কোড যুক্ত হয়েছে, এবং উইন্ডোজ জবসের লিঙ্ক

আমি এই সমস্যাটি সনাক্ত করার জন্য কিছু সময় ব্যয় করেছি এবং সেই সময় এক্সট্রিমভিবিটালক ছিল সর্বাধিক সক্রিয় এবং প্রতিক্রিয়াশীল। এখানে আপনার আসল পোস্টের লিঙ্ক, একটি এক্সেল ইন্টারপ প্রক্রিয়া পরিষ্কারভাবে বন্ধ করে দেওয়া হচ্ছে, এমনকি যদি আপনার অ্যাপ্লিকেশন ক্রাশ হয় । নীচে পোস্টের সংক্ষিপ্তসার এবং কোডটি এই পোস্টে অনুলিপি করা হয়েছে।

  • ইন্টারপ প্রক্রিয়াটি বন্ধ করে দেওয়া Application.Quit()এবং Process.Kill()বেশিরভাগ অংশের জন্য কাজ করে, তবে অ্যাপ্লিকেশনগুলি বিপর্যয়করভাবে ক্র্যাশ হলে ব্যর্থ হয়। উদাহরণস্বরূপ, যদি অ্যাপটি ক্র্যাশ হয়ে যায় তবে এক্সেল প্রক্রিয়াটি এখনও শিথিল হয়ে থাকবে।
  • সমাধানটি হ'ল উইন 32 কলগুলি ব্যবহার করে উইন্ডোজ জব অবজেক্টগুলির মাধ্যমে ওএস আপনার প্রসেসগুলির ক্লিনআপ পরিচালনা করতে দেয় । আপনার মূল অ্যাপ্লিকেশনটি মারা গেলে, সম্পর্কিত প্রক্রিয়াগুলি (যেমন এক্সেল) পাশাপাশি সমাপ্ত হবে।

আমি এটি একটি পরিষ্কার সমাধান হিসাবে পেয়েছি কারণ ওএস পরিস্কার করার আসল কাজ করছে। আপনাকে যা করতে হবে তা হ'ল এক্সেল প্রক্রিয়াটি নিবন্ধন করতে হবে ।

উইন্ডোজ জব কোড

আন্তোপ প্রক্রিয়াগুলি নিবন্ধিত করতে উইন 32 এপিআই কলগুলিকে মোড়ানো।

public enum JobObjectInfoType
{
    AssociateCompletionPortInformation = 7,
    BasicLimitInformation = 2,
    BasicUIRestrictions = 4,
    EndOfJobTimeInformation = 6,
    ExtendedLimitInformation = 9,
    SecurityLimitInformation = 5,
    GroupInformation = 11
}

[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
    public int nLength;
    public IntPtr lpSecurityDescriptor;
    public int bInheritHandle;
}

[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
    public Int64 PerProcessUserTimeLimit;
    public Int64 PerJobUserTimeLimit;
    public Int16 LimitFlags;
    public UInt32 MinimumWorkingSetSize;
    public UInt32 MaximumWorkingSetSize;
    public Int16 ActiveProcessLimit;
    public Int64 Affinity;
    public Int16 PriorityClass;
    public Int16 SchedulingClass;
}

[StructLayout(LayoutKind.Sequential)]
struct IO_COUNTERS
{
    public UInt64 ReadOperationCount;
    public UInt64 WriteOperationCount;
    public UInt64 OtherOperationCount;
    public UInt64 ReadTransferCount;
    public UInt64 WriteTransferCount;
    public UInt64 OtherTransferCount;
}

[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
    public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
    public IO_COUNTERS IoInfo;
    public UInt32 ProcessMemoryLimit;
    public UInt32 JobMemoryLimit;
    public UInt32 PeakProcessMemoryUsed;
    public UInt32 PeakJobMemoryUsed;
}

public class Job : IDisposable
{
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
    static extern IntPtr CreateJobObject(object a, string lpName);

    [DllImport("kernel32.dll")]
    static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);

    private IntPtr m_handle;
    private bool m_disposed = false;

    public Job()
    {
        m_handle = CreateJobObject(null, null);

        JOBOBJECT_BASIC_LIMIT_INFORMATION info = new JOBOBJECT_BASIC_LIMIT_INFORMATION();
        info.LimitFlags = 0x2000;

        JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
        extendedInfo.BasicLimitInformation = info;

        int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
        IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length);
        Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);

        if (!SetInformationJobObject(m_handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length))
            throw new Exception(string.Format("Unable to set information.  Error: {0}", Marshal.GetLastWin32Error()));
    }

    #region IDisposable Members

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    #endregion

    private void Dispose(bool disposing)
    {
        if (m_disposed)
            return;

        if (disposing) {}

        Close();
        m_disposed = true;
    }

    public void Close()
    {
        Win32.CloseHandle(m_handle);
        m_handle = IntPtr.Zero;
    }

    public bool AddProcess(IntPtr handle)
    {
        return AssignProcessToJobObject(m_handle, handle);
    }

}

কনস্ট্রাক্টর কোড সম্পর্কে নোট

  • কনস্ট্রাক্টরে, info.LimitFlags = 0x2000;বলা হয়। 0x2000হয় JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSEenum মান, এবং এই মান দ্বারা সংজ্ঞায়িত করা হয় দুটিই MSDN হিসাবে:

কাজের শেষ হ্যান্ডেলটি বন্ধ হয়ে গেলে কাজের সাথে যুক্ত সমস্ত প্রক্রিয়া বন্ধ হয়ে যায়।

প্রক্রিয়া আইডি (পিআইডি) পেতে অতিরিক্ত উইন 32 এপিআই কল

    [DllImport("user32.dll", SetLastError = true)]
    public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

কোড ব্যবহার করে

    Excel.Application app = new Excel.ApplicationClass();
    Job job = new Job();
    uint pid = 0;
    Win32.GetWindowThreadProcessId(new IntPtr(app.Hwnd), out pid);
    job.AddProcess(Process.GetProcessById((int)pid).Handle);

2
প্রসেস অফ আউট-প্রসেস COM সার্ভারকে হত্যা করা (এটি অন্যান্য সিওএম ক্লায়েন্টদের পরিবেশন করা হতে পারে) একটি ভয়ঙ্কর ধারণা। যদি আপনি এটির অবলম্বন করছেন তবে এটি আপনার সিওএম প্রোটোকলটি নষ্ট হয়ে গেছে। সিওএম সার্ভারগুলিকে নিয়মিত
উইন্ডোড

38

এটি যে প্রকল্পে আমি কাজ করছিলাম তার জন্য এটি কাজ করেছে:

excelApp.Quit();
Marshal.ReleaseComObject (excelWB);
Marshal.ReleaseComObject (excelApp);
excelApp = null;

আমরা শিখেছি যে কোনও এক্সেল সিওএম অবজেক্টের প্রতিটি রেফারেন্সটি আপনার সাথে করা হয়ে গেলে নালায় সেট করা গুরুত্বপূর্ণ ছিল । এর মধ্যে সেল, পত্রক এবং সমস্ত কিছু অন্তর্ভুক্ত ছিল।


30

এক্সেল নেমস্পেসে থাকা যে কোনও কিছুই প্রকাশ করা দরকার। কাল

আপনি করছেন না:

Worksheet ws = excel.WorkBooks[1].WorkSheets[1];

আপনি করতে হবে

Workbooks books = excel.WorkBooks;
Workbook book = books[1];
Sheets sheets = book.WorkSheets;
Worksheet ws = sheets[1];

অবজেক্টগুলি প্রকাশের পরে।


3
উদাহরণস্বরূপ কীভাবে এওবুট xlRange.Interior.Color।
এইডেস

অভ্যন্তরীণ রিলিজ (তার নামস্থান মধ্যে) করা প্রয়োজন ... রঙ অন্যদিকে নেই (তার System.Drawing.Color থেকে iirc কারণ)
MagicKat

2
প্রকৃতপক্ষে রঙ একটি এক্সেল রঙ। নেট রঙ নয়। আপনি শুধু একটি দীর্ঘ পাস। ওয়ার্কবুক ডিএফ। রিলিজ করা দরকার, ওয়ার্কশিট ... এত কম।
বেনামে টাইপ

এটি সত্য নয়, দুই-ডট-খারাপ, এক-ডট-ভাল নিয়মটি বোকামি। এছাড়াও, আপনাকে ওয়ার্কবুকস, ওয়ার্কশিট, রেঞ্জগুলি প্রকাশ করতে হবে না, এটি জিসির কাজ। একমাত্র জিনিসটি যা আপনি কখনই ভুলে যাবেন না তা হ'ল একমাত্র এবং কেবলমাত্র এক্সেল.এপ্লিকেশন অবজেক্টে প্রস্থান করুন। প্রস্থান কল করার পরে, এক্সেলটি বাতিল করুন lic অ্যাপ্লিকেশন অবজেক্টটি কল করুন এবং জিসি.ক্ল্যাক্ট () কল করুন; GC.WaitForPendingFinalizers (); দুইবার।
ডায়েটরিচ বামগার্টেন

29

প্রথম - আপনাকে কখনই কল করতে হবে নাMarshal.ReleaseComObject(...) বা Marshal.FinalReleaseComObject(...)এক্সেল ইন্টারপ করার সময়। এটি একটি বিভ্রান্তিমূলক অ্যান্টি-প্যাটার্ন, তবে মাইক্রোসফ্ট সহ এই সম্পর্কিত কোনও তথ্য যা ইঙ্গিত করে যে আপনাকে .NET থেকে ম্যানুয়ালি COM রেফারেন্স প্রকাশ করতে হবে is আসল বিষয়টি হ'ল। নেট রানটাইম এবং আবর্জনা সংগ্রহকারী সঠিকভাবে COM উল্লেখগুলি ট্র্যাক করে এবং পরিষ্কার করে। আপনার কোডের জন্য, এর অর্থ আপনি শীর্ষে থাকা পুরো (যখন) লুপটি সরাতে পারেন।

দ্বিতীয়ত, আপনি যদি নিশ্চিত করতে চান যে আপনার প্রক্রিয়াটি শেষ হওয়ার পরে কোনও বহির্মুখী COM অবজেক্টের COM উল্লেখগুলি পরিষ্কার হয়ে যায় (যাতে এক্সেল প্রক্রিয়াটি বন্ধ হয়ে যায়), আপনার আবশ্যক আবর্জনা সংগ্রহকারী চলমান তা নিশ্চিত করতে হবে। আপনি কল GC.Collect()এবং এর মাধ্যমে সঠিকভাবে এটি করছেন GC.WaitForPendingFinalizers()। এটিকে দু'বার কল করা নিরাপদ, এবং নিশ্চিত করে যে চক্রগুলি অবশ্যই খুব পরিষ্কার হয়ে গেছে (যদিও আমি নিশ্চিত নই যে এটির প্রয়োজন আছে, এবং এটি উদাহরণ দেখায় যে এটি উপলব্ধি করবে) appreciate

তৃতীয়ত, ডিবাগারের নিচে চলার সময়, স্থানীয় রেফারেন্সগুলি কৃত্রিমভাবে পদ্ধতিটির শেষ অবধি জীবিত রাখা হবে (যাতে স্থানীয় পরিবর্তনশীল পরিদর্শন কাজ করে)। সুতরাং GC.Collect()কলগুলি rng.Cellsএকই পদ্ধতি থেকে অবজেক্ট পরিষ্কার করার জন্য কার্যকর নয় । আপনার জিসি ক্লিনআপ থেকে সিওএম ইন্টারপ করার কোডটি পৃথক পদ্ধতিতে বিভক্ত করা উচিত। (@ নাইটকোডার এখানে পোস্ট করা উত্তরের একটি অংশ থেকে এটি আমার জন্য একটি মূল আবিষ্কার ছিল))

সাধারণ প্যাটার্নটি এইভাবে হবে:

Sub WrapperThatCleansUp()

    ' NOTE: Don't call Excel objects in here... 
    '       Debugger would keep alive until end, preventing GC cleanup

    ' Call a separate function that talks to Excel
    DoTheWork()

    ' Now let the GC clean up (twice, to clean up cycles too)
    GC.Collect()    
    GC.WaitForPendingFinalizers()
    GC.Collect()    
    GC.WaitForPendingFinalizers()

End Sub

Sub DoTheWork()
    Dim app As New Microsoft.Office.Interop.Excel.Application
    Dim book As Microsoft.Office.Interop.Excel.Workbook = app.Workbooks.Add()
    Dim worksheet As Microsoft.Office.Interop.Excel.Worksheet = book.Worksheets("Sheet1")
    app.Visible = True
    For i As Integer = 1 To 10
        worksheet.Cells.Range("A" & i).Value = "Hello"
    Next
    book.Save()
    book.Close()
    app.Quit()

    ' NOTE: No calls the Marshal.ReleaseComObject() are ever needed
End Sub

এমএসডিএন এবং স্ট্যাক ওভারফ্লোতে (এবং বিশেষত এই প্রশ্নটি!) অনেকগুলি পোস্ট সহ এই সমস্যাটি সম্পর্কে প্রচুর ভ্রান্ত তথ্য এবং বিভ্রান্তি রয়েছে।

কি পরিশেষে আমার দৃঢ় বিশ্বাস আউট অধিকার পরামর্শ পুরো বিষয়টা বিস্তারিত বিবেচনা এবং চিত্র আছে ব্লগ পোস্ট ছিল Marshal.ReleaseComObject বিবেচনা বিপজ্জনক ইস্যু খোঁজার সঙ্গে রেফারেন্স ডিবাগার যে আমার আগের পরীক্ষামূলক বিভ্রান্তিকর ছিল অধীনে বাঁচিয়ে রেখেছে একসাথে।


5
এই পৃষ্ঠাতে কার্যত সমস্ত উত্তরগুলি এই একটিকে ছাড়িয়ে দিন। তারা কাজ কিন্তু উপায় অনেক বেশি কাজ। "2 ডটস" বিধিটি অগ্রাহ্য করুন। জিসি আপনার জন্য আপনার কাজটি করতে দিন। । নেট গুরু গুরু হান্স প্যাস্যান্টের পরিপূরক প্রমাণ: স্ট্যাকওভারফ্লো.
25135685

1
Govert, এটি করার সঠিক উপায়টি খুঁজে পাওয়ার জন্য কী ত্রাণ। ধন্যবাদ.
ডায়েত্রিচ বামগার্টেন

18

আমি একটি দরকারী জেনেরিক টেম্পলেট পেয়েছি যা COM অবজেক্টগুলির জন্য সঠিক নিষ্পত্তি প্যাটার্ন কার্যকর করতে সহায়তা করতে পারে, যার জন্য মার্শাল দরকার e

ব্যবহার:

using (AutoReleaseComObject<Application> excelApplicationWrapper = new AutoReleaseComObject<Application>(new Application()))
{
    try
    {
        using (AutoReleaseComObject<Workbook> workbookWrapper = new AutoReleaseComObject<Workbook>(excelApplicationWrapper.ComObject.Workbooks.Open(namedRangeBase.FullName, false, false, missing, missing, missing, true, missing, missing, true, missing, missing, missing, missing, missing)))
        {
           // do something with your workbook....
        }
    }
    finally
    {
         excelApplicationWrapper.ComObject.Quit();
    } 
}

টেমপ্লেট:

public class AutoReleaseComObject<T> : IDisposable
{
    private T m_comObject;
    private bool m_armed = true;
    private bool m_disposed = false;

    public AutoReleaseComObject(T comObject)
    {
        Debug.Assert(comObject != null);
        m_comObject = comObject;
    }

#if DEBUG
    ~AutoReleaseComObject()
    {
        // We should have been disposed using Dispose().
        Debug.WriteLine("Finalize being called, should have been disposed");

        if (this.ComObject != null)
        {
            Debug.WriteLine(string.Format("ComObject was not null:{0}, name:{1}.", this.ComObject, this.ComObjectName));
        }

        //Debug.Assert(false);
    }
#endif

    public T ComObject
    {
        get
        {
            Debug.Assert(!m_disposed);
            return m_comObject;
        }
    }

    private string ComObjectName
    {
        get
        {
            if(this.ComObject is Microsoft.Office.Interop.Excel.Workbook)
            {
                return ((Microsoft.Office.Interop.Excel.Workbook)this.ComObject).Name;
            }

            return null;
        }
    }

    public void Disarm()
    {
        Debug.Assert(!m_disposed);
        m_armed = false;
    }

    #region IDisposable Members

    public void Dispose()
    {
        Dispose(true);
#if DEBUG
        GC.SuppressFinalize(this);
#endif
    }

    #endregion

    protected virtual void Dispose(bool disposing)
    {
        if (!m_disposed)
        {
            if (m_armed)
            {
                int refcnt = 0;
                do
                {
                    refcnt = System.Runtime.InteropServices.Marshal.ReleaseComObject(m_comObject);
                } while (refcnt > 0);

                m_comObject = default(T);
            }

            m_disposed = true;
        }
    }
}

রেফারেন্স:

http://www.deez.info/sengelha/2005/02/11/useful-idisposable-class-3-autoreleasecomobject/


3
হ্যাঁ এই এক ভাল। আমি মনে করি এই কোডটি হালনাগাদ করা যেতে পারে যদিও এখন ফাইনালিলিজলকম-অবজেক্ট পাওয়া যায়।
বেনামে টাইপ

প্রতিটি বস্তুর জন্য ব্যবহারের ব্লক থাকা এখনও বিরক্তিকর। বিকল্পের জন্য এখানে স্ট্যাকওভারফ্লো . com/ প্রশ্নগুলি / 2191489/… দেখুন ।
হেনরিক

16

আমি বিশ্বাস করতে পারি না এই সমস্যাটি বিশ্বটিকে 5 বছরের জন্য হান্ট করেছে .... আপনি যদি কোনও অ্যাপ্লিকেশন তৈরি করে থাকেন তবে লিঙ্কটি সরিয়ে নেওয়ার আগে আপনাকে প্রথমে এটিকে বন্ধ করতে হবে।

objExcel = new Excel.Application();  
objBook = (Excel.Workbook)(objExcel.Workbooks.Add(Type.Missing)); 

বন্ধ যখন

objBook.Close(true, Type.Missing, Type.Missing); 
objExcel.Application.Quit();
objExcel.Quit(); 

আপনি যখন একটি এক্সেল অ্যাপ্লিকেশন নতুন করেন, তখন এটি ব্যাকগ্রাউন্ডে একটি এক্সেল প্রোগ্রাম খোলে। লিঙ্কটি প্রকাশের আগে আপনাকে সেই এক্সেল প্রোগ্রামটি ছেড়ে দিতে আদেশ করতে হবে কারণ সেই এক্সেল প্রোগ্রামটি আপনার সরাসরি নিয়ন্ত্রণের অংশ নয়। সুতরাং, লিঙ্কটি প্রকাশিত হলে এটি উন্মুক্ত থাকবে!

সবাই ভালো প্রোগ্রামিং ~~


না, আপনি করবেন না, বিশেষত যদি আপনি COM অ্যাপ্লিকেশনটির সাথে ব্যবহারকারীর ইন্টারঅ্যাকশনকে মঞ্জুরি দিতে চান তবে (এই ক্ষেত্রে এক্সেল - ওপি ব্যবহারকারী ইন্টারঅ্যাকশনটি নির্দিষ্ট করে কিনা তা নির্দিষ্ট করে না তবে এটি বন্ধ করার বিষয়ে কোনও রেফারেন্স দেয় না)। একমাত্র ফাইল বন্ধ করার সময়, এক্সেলটি ছাড়তে সক্ষম হওয়ার জন্য ব্যবহারকারীকে আপনাকে কেবল কলারকে যেতে হবে say
ডাউনউইচ

এটি আমার জন্য নিখুঁতভাবে কাজ করেছে - যখন কেবলমাত্র আমিজিস্টেল.কুইট () ছিলাম তখন আমি ক্র্যাশ হয়ে গিয়েছিলাম, কিন্তু যখন আমি আগেও আপত্তি করেছি .এপ্লিকেশন.কুইট () পূর্বে, পরিষ্কারভাবে বন্ধ হয়ে গিয়েছিল।
এমসিএমিলাব

13

সাধারণ বিকাশকারী, আপনার কোনও সমাধান আমার পক্ষে কাজ করেনি, তাই আমি একটি নতুন কৌশল বাস্তবায়নের সিদ্ধান্ত নিই ।

প্রথমে উল্লেখ করা যাক "আমাদের লক্ষ্য কী?" => "টাস্ক ম্যানেজারে আমাদের কাজের পরে এক্সেল অবজেক্টটি দেখতে পাচ্ছেন না"

ঠিক আছে. এটিকে চ্যালেঞ্জ জানাতে এবং এটি ধ্বংস করতে না দেওয়া উচিত, তবে সমান্তরালভাবে চলছে এমন অন্যান্য উদাহরণ ওএস এক্সেলকে না ধ্বংস করার বিষয়ে বিবেচনা করুন।

সুতরাং, বর্তমান প্রসেসরের তালিকা পান এবং এক্সেল প্রসেসের পিআইডি আনুন, তারপরে আপনার কাজটি শেষ হয়ে গেলে, আমরা একটি অনন্য পিআইডি সহ প্রসেস তালিকায় একটি নতুন অতিথি পেয়েছি, ঠিক সেইটিকে সন্ধান করুন এবং ধ্বংস করুন।

<আপনার এক্সেল কাজের সময় যে কোনও নতুন এক্সেল প্রক্রিয়া মনে রাখবেন নতুন এবং ধ্বংস হিসাবে সনাক্ত করা হবে> <আরও ভাল সমাধান হ'ল নতুন তৈরি এক্সেল অবজেক্টের পিআইডি ক্যাপচার করা এবং কেবল এটি>

Process[] prs = Process.GetProcesses();
List<int> excelPID = new List<int>();
foreach (Process p in prs)
   if (p.ProcessName == "EXCEL")
       excelPID.Add(p.Id);

.... // your job 

prs = Process.GetProcesses();
foreach (Process p in prs)
   if (p.ProcessName == "EXCEL" && !excelPID.Contains(p.Id))
       p.Kill();

এটি আমার সমস্যাটির সমাধান করে, আশা করি আপনারও।


1
.... এটি একটি স্লেডগ্যামার পদ্ধতির কিছুটা? - আমি যা ব্যবহার করছি এটির সাথে এটি একইরকম :( তবে পরিবর্তিত হওয়া দরকার this এই পদ্ধতির সাহায্যে সমস্যাটি হ'ল প্রায়শই এক্সেল খোলার সময়, মেশিনে যেখানে এটি দৌড়ায়, এটির বাম হাতের বারে সতর্কতা থাকে, যা কিছু বলেছিল) "এক্সেল ভুলভাবে বন্ধ করে দেওয়া হয়েছিল": খুব মার্জিত নয় I আমার মনে হয় এই থ্রেডের আগের পরামর্শগুলির মধ্যে একটি পছন্দ করা উচিত
কেন

11

এটি নিশ্চিত মনে হচ্ছে এটি অত্যধিক জটিল হয়েছে। আমার অভিজ্ঞতা থেকে, এক্সেলকে সঠিকভাবে বন্ধ করার জন্য কেবল তিনটি মূল বিষয় রয়েছে:

1: নিশ্চিত হয়ে নিন যে আপনি যে এক্সেল অ্যাপ্লিকেশনটি তৈরি করেছেন তার কোনও অবশিষ্ট রেফারেন্স নেই (আপনার কেবল যাইহোক একটি হওয়া উচিত; এটিতে সেট করুন null)

2: কল GC.Collect()

3: এক্সেলটি ব্যবহারকারীকে ম্যানুয়ালি প্রোগ্রামটি বন্ধ করে দিয়ে, অথবা আপনি Quitএক্সেল অবজেক্টে কল করে এক্সেলটি বন্ধ করতে হবে । (দ্রষ্টব্য এটি Quitঠিক তেমনভাবে কাজ করবে যেহেতু ব্যবহারকারী প্রোগ্রামটি বন্ধ করার চেষ্টা করেছেন এবং এক্সেলটি দৃশ্যমান না থাকলেও সংরক্ষণে না থাকা পরিবর্তনগুলি থাকলে একটি নিশ্চিতকরণ ডায়ালগ উপস্থাপন করবেন The ব্যবহারকারী বাতিল চাপতে পারে, এবং এক্সেলটি বন্ধ করা হত না। )

1 টি 2 এর আগে ঘটতে হবে তবে 3 টি যে কোনও সময় ঘটতে পারে।

এটি প্রয়োগের একটি উপায় হ'ল আন্তঃব্যক্তিক এক্সেল অবজেক্টটি আপনার নিজের শ্রেণীর সাথে মোড়ানো, কনস্ট্রাক্টরের মধ্যে ইন্টারপ উদাহরণ তৈরি করা, এবং ডিসপোজ সহ আইডিজিপোজেবলের মতো কিছু দেখতে লাগানো implement

if (!mDisposed) {
   mExcel = null;
   GC.Collect();
   mDisposed = true;
}

এটি আপনার প্রোগ্রামের জিনিসগুলি থেকে এক্সেল সাফ করবে। একবার এক্সেল বন্ধ হয়ে যাওয়ার পরে (ব্যবহারকারীর দ্বারা বা আপনি কল করার মাধ্যমে Quit) প্রক্রিয়াটি চলে যাবে। যদি প্রোগ্রামটি ইতিমধ্যে বন্ধ হয়ে গেছে, তবে প্রক্রিয়াটি GC.Collect()কলটিতে অদৃশ্য হয়ে যাবে ।

(এটি কতটা গুরুত্বপূর্ণ তা আমি নিশ্চিত নই, তবে আপনি GC.WaitForPendingFinalizers()কল করার পরে কল চাইতে GC.Collect()পারেন তবে এক্সেল প্রক্রিয়া থেকে মুক্তি পাওয়ার পক্ষে কঠোরভাবে প্রয়োজন হয় না))

এটি বছরের পর বছর ইস্যু ছাড়াই আমার পক্ষে কাজ করেছে। মনে রাখবেন যে এটি কাজ করার সময়, আপনাকে এটির কাজ করার জন্য প্রকৃতপক্ষে চমত্কারভাবে বন্ধ করতে হবে। এক্সেল পরিষ্কার হওয়ার আগে আপনি যদি আপনার প্রোগ্রামটি বাধাগ্রহণ করেন তবে আপনি সাধারণত এক্সেল.এক্স.সি প্রক্রিয়াগুলি সংগ্রহ করবেন (সাধারণত আপনার প্রোগ্রামটি ডিবাগ করার সময় "স্টপ" টিপুন)।


1
এই উত্তরটি কাজ করে এবং স্বীকৃত উত্তরের চেয়ে অসীম সুবিধাজনক। COM অবজেক্টস সহ "দুটি বিন্দু" নিয়ে কোনও উদ্বেগ নেই, ব্যবহার নেই Marshal
andrew.cuthbert 26'15

9

এক্সেল বন্ধ না হওয়ার কারণগুলি যুক্ত করার জন্য, আপনি যখন পড়ার, তৈরির উপরে প্রতিটি বস্তুর প্রত্যক্ষ রেফ্রান্স তৈরি করেন তখন এটি 'ফর' লুপ।

For Each objWorkBook As WorkBook in objWorkBooks 'local ref, created from ExcelApp.WorkBooks to avoid the double-dot
   objWorkBook.Close 'or whatever
   FinalReleaseComObject(objWorkBook)
   objWorkBook = Nothing
Next 

'The above does not work, and this is the workaround:

For intCounter As Integer = 1 To mobjExcel_WorkBooks.Count
   Dim objTempWorkBook As Workbook = mobjExcel_WorkBooks.Item(intCounter)
   objTempWorkBook.Saved = True
   objTempWorkBook.Close(False, Type.Missing, Type.Missing)
   FinalReleaseComObject(objTempWorkBook)
   objTempWorkBook = Nothing
Next

এবং অন্য কারণ, পূর্ববর্তী মানটি প্রথমে প্রকাশ না করেই পুনরায় ব্যবহার করুন।
গ্রিমফর্ট

ধন্যবাদ. আপনার সমাধানটি আমার পক্ষে কাজ করেছিল আমি "প্রত্যেকের জন্য "ও ব্যবহার করছিলাম।
চাদ ব্রাউন-ডুইন

+1 ধন্যবাদ এছাড়াও, নোট করুন যে আপনার যদি কোনও এক্সেল পরিসরের জন্য কোনও বস্তু থাকে এবং আপনি যদি সেই অবজেক্টের জীবদ্দশায় রেঞ্জটি পরিবর্তন করতে চান তবে আমি দেখতে পেলাম যে এটি পুনরায় অর্পণ করার আগে আমাকে রিলিজকমঅবজেক্ট করতে হয়েছিল, যা কোডটি কিছুটা অস্বচ্ছল করে তোলে!
আজভি জেসি

9

আমি tradition তিহ্যগতভাবে ভিভিএসের উত্তরে প্রাপ্ত পরামর্শ অনুসরণ করেছি । তবে এই উত্তরটি সর্বশেষ বিকল্পগুলির সাথে আপ-টু-ডেট রাখার প্রয়াসে, আমি মনে করি আমার ভবিষ্যতের সমস্ত প্রকল্পগুলি "নেটঅফিস" লাইব্রেরিটি ব্যবহার করবে।

নেটওফিস অফিস পিআইএগুলির সম্পূর্ণ প্রতিস্থাপন এবং এটি সম্পূর্ণ সংস্করণ-অজোনস্টিক। এটি ম্যানেজড সিওএম র‌্যাপারগুলির একটি সংগ্রহ যা ক্লিনআপটি পরিচালনা করতে পারে যা। নেট এ মাইক্রোসফ্ট অফিসের সাথে কাজ করার সময় প্রায়শই এ জাতীয় মাথা ব্যথার কারণ হয়ে দাঁড়ায়।

কয়েকটি মূল বৈশিষ্ট্য হ'ল:

  • বেশিরভাগ সংস্করণ-স্বতন্ত্র (এবং সংস্করণ-নির্ভর বৈশিষ্ট্যগুলি নথিভুক্ত করা হয়)
  • কোনও নির্ভরতা নেই
  • পিআইএ নেই
  • কোনও নিবন্ধকরণ নেই
  • ভিএসটিও নেই

আমি কোনওভাবেই প্রকল্পের সাথে সম্পৃক্ত নই; আমি কেবল মাথা ব্যথার একেবারে হ্রাস প্রশংসনীয়।


2
এটি উত্তর হিসাবে চিহ্নিত করা উচিত, সত্যই। নেটওফিস এই সমস্ত জটিলতা দূরে সরিয়ে দেয়।
সি আগস্টো প্রিয়েটে

1
আমি নেটঅফিসটি একটি এক্সেল অ্যাড-ইন লেখার জন্য যথেষ্ট পরিমাণে ব্যবহার করেছি এবং এটি পুরোপুরি কার্যকর হয়েছে। কেবলমাত্র বিবেচনার বিষয় হ'ল আপনি যদি ব্যবহৃত বস্তুগুলিকে স্পষ্টভাবে নিষ্পত্তি না করেন তবে আপনি অ্যাপ্লিকেশন থেকে বেরিয়ে আসার সময় এটি তা করবে (কারণ এটি যেভাবেই তাদের ট্র্যাক করে রাখে)। সুতরাং নেটওফিসের সাথে থাম্বের নিয়মটি সর্বদা প্রতিটি এক্সেল অবজেক্ট যেমন সেল, ব্যাপ্তি বা শিট ইত্যাদির সাথে "ব্যবহার" প্যাটার্ন ব্যবহার করা হয়
স্টাস ইভানভ

8

এখানে গৃহীত উত্তর সঠিক, তবে এটিও খেয়াল করুন যে কেবলমাত্র "দুটি ডট" রেফারেন্স এড়ানো প্রয়োজন, তবে সূচিগুলির মাধ্যমে পুনরুদ্ধার করা অবজেক্টগুলিও। এই বিষয়গুলি পরিষ্কার করার জন্য আপনি প্রোগ্রামটি শেষ না হওয়া পর্যন্ত আপনাকে অপেক্ষা করারও দরকার নেই, ফাংশনগুলি তৈরি করা ভাল যা আপনি যখন সম্ভব শেষ করার সাথে সাথে এগুলি পরিষ্কার করবেন ততক্ষণে এটি পরিষ্কার করা উচিত। এখানে আমি তৈরি একটি ফাংশন যা একটি স্টাইল অবজেক্টের কিছু বৈশিষ্ট্য নির্ধারণ করে xlStyleHeader:

public Excel.Style xlStyleHeader = null;

private void CreateHeaderStyle()
{
    Excel.Styles xlStyles = null;
    Excel.Font xlFont = null;
    Excel.Interior xlInterior = null;
    Excel.Borders xlBorders = null;
    Excel.Border xlBorderBottom = null;

    try
    {
        xlStyles = xlWorkbook.Styles;
        xlStyleHeader = xlStyles.Add("Header", Type.Missing);

        // Text Format
        xlStyleHeader.NumberFormat = "@";

        // Bold
        xlFont = xlStyleHeader.Font;
        xlFont.Bold = true;

        // Light Gray Cell Color
        xlInterior = xlStyleHeader.Interior;
        xlInterior.Color = 12632256;

        // Medium Bottom border
        xlBorders = xlStyleHeader.Borders;
        xlBorderBottom = xlBorders[Excel.XlBordersIndex.xlEdgeBottom];
        xlBorderBottom.Weight = Excel.XlBorderWeight.xlMedium;
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        Release(xlBorderBottom);
        Release(xlBorders);
        Release(xlInterior);
        Release(xlFont);
        Release(xlStyles);
    }
}

private void Release(object obj)
{
    // Errors are ignored per Microsoft's suggestion for this type of function:
    // http://support.microsoft.com/default.aspx/kb/317109
    try
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
    }
    catch { } 
}

লক্ষ্য করুন যে এটি xlBorders[Excel.XlBordersIndex.xlEdgeBottom]পরিষ্কার করার জন্য আমাকে একটি ভেরিয়েবল সেট করতে হয়েছিল (দুটি বিন্দুর কারণে নয়, যা একটি গণনাকে প্রকাশ করার দরকার নেই যা মুক্তি দেওয়ার দরকার নেই, তবে কারণ আমি যে অবজেক্টটি উল্লেখ করছি সেটি আসলে একটি বর্ডার অবজেক্ট এটি প্রকাশ করা দরকার)।

স্ট্যান্ডার্ড অ্যাপ্লিকেশনগুলিতে এই ধরণের জিনিসটি সত্যই প্রয়োজন হয় না, যা নিজের পরে পরিষ্কার করার দুর্দান্ত কাজ করে তবে এএসপি.এনইটি অ্যাপ্লিকেশনগুলিতে, আপনি যদি এর মধ্যে একটিও মিস করেন তবে যতবারই আপনি আবর্জনা সংগ্রহকারীকে কল করেন না কেন এক্সেল করবে এখনও আপনার সার্ভারে চলমান।

এই কোডটি লেখার সময় টাস্ক ম্যানেজারকে পর্যবেক্ষণ করার সময় এটির বিশদ এবং অনেকগুলি পরীক্ষামূলক মৃত্যুদণ্ডের দিকে মনোযোগ প্রয়োজন, তবে এটি করার ফলে আপনি কোডটি পৃষ্ঠাতে সন্ধান করার ঝামেলা বাঁচিয়ে ফেলেছেন যে কোনও একটি উদাহরণ খুঁজে পেয়েছেন find লুপগুলিতে কাজ করার সময় এটি বিশেষত গুরুত্বপূর্ণ, যেখানে আপনাকে যখন কোনও বস্তুর প্রতিটি ইনস্ট্যান্স প্রকাশ করতে হবে, যদিও এটি প্রতিবার লুপ করে একই পরিবর্তনশীল নামটি ব্যবহার করে।


রিলিজের অভ্যন্তরে, নলের জন্য পরীক্ষা করুন (জো এর উত্তর)। এটি অপ্রয়োজনীয় নাল ব্যতিক্রম এড়াতে পারবে। আমি প্রচুর পদ্ধতি পরীক্ষা করেছি। এক্সেলকে কার্যকরভাবে প্রকাশের একমাত্র উপায় এটি।
জেরহার্ড পাওয়েল

8

চেষ্টা করার পরে

  1. বিপরীত ক্রমে COM অবজেক্টগুলি ছেড়ে দিন
  2. যোগ করুন GC.Collect()এবং GC.WaitForPendingFinalizers()শেষে দুইবার
  3. দুটি বিন্দুর বেশি নয়
  4. ওয়ার্কবুক বন্ধ করুন এবং অ্যাপ্লিকেশনটি ছেড়ে দিন
  5. রিলিজ মোডে চালান

আমার জন্য কাজ করে এমন চূড়ান্ত সমাধানটি হ'ল এক সেট সরানো

GC.Collect();
GC.WaitForPendingFinalizers();

যেটি আমরা ফাংশনটির শেষে একটি মোড়কে যুক্ত করেছি:

private void FunctionWrapper(string sourcePath, string targetPath)
{
    try
    {
        FunctionThatCallsExcel(sourcePath, targetPath);
    }
    finally
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

আমি খুঁজে পেয়েছি যে আমার ComObjects বাতিল করার দরকার নেই, কেবল প্রস্থান () - বন্ধ () এবং ফাইনাল রিলিজকোবজেক্ট। আমি বিশ্বাস করতে পারি না যে এটি আমার কাজ শেষ করার জন্য হারিয়ে গেছে। গ্রেট!
ক্যারল 21

7

আমি একেবারে অনুসরণ করেছি ... তবে আমি এখনও 1000 বারের মধ্যে 1 ইস্যুতে ছুটেছি। কে জানে কেন। হাতুড়ি বের করার সময় ...

এক্সেল অ্যাপ্লিকেশন ক্লাসটি ইনস্ট্যান্ট করার ঠিক পরে আমি সবেমাত্র তৈরি হওয়া এক্সেল প্রক্রিয়াটির একটি হোল্ড পাই।

excel = new Microsoft.Office.Interop.Excel.Application();
var process = Process.GetProcessesByName("EXCEL").OrderByDescending(p => p.StartTime).First();

তারপরে একবার আমি উপরের সমস্ত সিওএম ক্লিনআপ শেষ করে নেব, আমি নিশ্চিত করে নিই যে প্রক্রিয়াটি চলছে না। যদি এখনও চলতে থাকে তবে মেরে ফেল!

if (!process.HasExited)
   process.Kill();

7

Excel ° º¤ø „Excel এক্সেল প্রুকটি অঙ্কন করুন এবং বুদবুদ আঠা চিবান ¸„ ø¤º ° ¨

public class MyExcelInteropClass
{
    Excel.Application xlApp;
    Excel.Workbook xlBook;

    public void dothingswithExcel() 
    {
        try { /* Do stuff manipulating cells sheets and workbooks ... */ }
        catch {}
        finally {KillExcelProcess(xlApp);}
    }

    static void KillExcelProcess(Excel.Application xlApp)
    {
        if (xlApp != null)
        {
            int excelProcessId = 0;
            GetWindowThreadProcessId(xlApp.Hwnd, out excelProcessId);
            Process p = Process.GetProcessById(excelProcessId);
            p.Kill();
            xlApp = null;
        }
    }

    [DllImport("user32.dll")]
    static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);
}

6

আপনার সচেতন হওয়া দরকার যে এক্সেলটি যে সংস্কৃতিরও আপনি অধীনে চলেছেন তাতে খুব সংবেদনশীল।

আপনি দেখতে পাবেন যে এক্সেল ফাংশনগুলি কল করার আগে আপনাকে সংস্কৃতিটি EN-US এ সেট করতে হবে। এটি সমস্ত ফাংশনে প্রযোজ্য নয় - তবে কয়েকটি।

    CultureInfo en_US = new System.Globalization.CultureInfo("en-US"); 
    System.Threading.Thread.CurrentThread.CurrentCulture = en_US;
    string filePathLocal = _applicationObject.ActiveWorkbook.Path;
    System.Threading.Thread.CurrentThread.CurrentCulture = orgCulture;

আপনি ভিএসটিও ব্যবহার করলেও এটি প্রযোজ্য।

বিশদগুলির জন্য: http://support.microsoft.com/default.aspx?scid=kb ; en-us ; Q320369


6

সিওএম রেফারেন্স ফাঁস এড়াতে থাম্বের দুর্দান্ত নিয়ম "সিওএম অবজেক্টস সহ দুটি ডট কখনও ব্যবহার করবেন না" তবে এক্সেল পিআইএ প্রথম দর্শনে দৃশ্যমানের চেয়ে আরও বেশি উপায়ে ফুটো হতে পারে।

এই উপায়গুলির মধ্যে একটি হ'ল এক্সেল অবজেক্ট মডেলের COM অবজেক্টগুলির দ্বারা প্রকাশিত কোনও ইভেন্টের সদস্যতা নেওয়া।

উদাহরণস্বরূপ, অ্যাপ্লিকেশন শ্রেণীর ওয়ার্কবুক ওপেন ইভেন্টটিতে সদস্যতা নেওয়া।

সিওএম ইভেন্ট সম্পর্কিত কিছু তত্ত্ব

সিওএম ক্লাসগুলি কল-ব্যাক ইন্টারফেসের মাধ্যমে ইভেন্টের একটি গোষ্ঠী প্রকাশ করে। ইভেন্টগুলিতে সাবস্ক্রাইব করার জন্য, ক্লায়েন্ট কোডটি কেবল কল-ব্যাক ইন্টারফেস প্রয়োগকারী কোনও বিষয়টিকে নিবন্ধভুক্ত করতে পারে এবং সিওএম বর্গ নির্দিষ্ট ইভেন্টগুলির প্রতিক্রিয়াতে তার পদ্ধতিগুলি আহ্বান করবে। যেহেতু কল-ব্যাক ইন্টারফেসটি একটি সিওএম ইন্টারফেস, তাই ইভেন্ট হ্যান্ডলারের কোনওটির জন্য এটি প্রাপ্ত কোনও সিওএম অবজেক্টের (প্যারামিটার হিসাবে) রেফারেন্স গণনা হ্রাস করা বাস্তবায়নকারী অবজেক্টের কর্তব্য।

এক্সেল পিআইএ কীভাবে সিওএম ইভেন্টগুলি প্রকাশ করে

এক্সেল পিআইএ এক্সেল অ্যাপ্লিকেশন শ্রেণির সিওএম ইভেন্টগুলি প্রচলিত। নেট ইভেন্ট হিসাবে প্রকাশ করে। যখনই ক্লায়েন্ট কোড সদস্যতা একটি .NET ঘটনা ( 'একটি' ওপর গুরুত্ব), পিআইএ সৃষ্টি একটি একটি বর্গ কল-ব্যাক ইন্টারফেস এবং এটা রেজিস্টার এক্সেল সঙ্গে বাস্তবায়ন দৃষ্টান্ত।

অতএব, .NET কোড থেকে বিভিন্ন সাবস্ক্রিপশন অনুরোধের জবাবে বেশ কয়েকটি কল-ব্যাক অবজেক্টস এক্সেলের সাথে নিবন্ধিত হয়। ইভেন্টের সদস্যতার জন্য একটি কল-ব্যাক অবজেক্ট।

ইভেন্ট হ্যান্ডলিংয়ের জন্য একটি কল-ব্যাক ইন্টারফেসের অর্থ পিআইএর প্রত্যেকটি নেট নেটওয়ার্কের সাবস্ক্রিপশন অনুরোধের জন্য সমস্ত ইন্টারফেস ইভেন্টগুলিতে সাবস্ক্রাইব করতে হয়। এটি চয়ন বা চয়ন করতে পারে না। কোনও ইভেন্ট কল-ব্যাক পাওয়ার পরে, কল-ব্যাক অবজেক্টটি সম্পর্কিত। নেট ইভেন্ট হ্যান্ডলারটি বর্তমান ইভেন্টে আগ্রহী কিনা তা যাচাই করে এবং তারপরে হয় হ্যান্ডলারের কাছে প্রার্থনা করে বা চুপ করে কল-ব্যাক উপেক্ষা করে।

COM উদাহরণ রেফারেন্স গণনাগুলিতে প্রভাব

এই সমস্ত কল-ব্যাক অবজেক্টগুলি কল-ব্যাকের কোনও পদ্ধতির জন্য (এমনকি চুপচাপ উপেক্ষা করা হবে এমনগুলির জন্য) যে কোনও COM অবজেক্ট (প্যারামিটার হিসাবে) প্রাপ্ত তাদের রেফারেন্স গণনা হ্রাস করে না। তারা সিওএম অবজেক্টগুলি মুক্ত করতে কেবল সিএলআর আবর্জনা সংগ্রাহকের উপর নির্ভর করে ।

যেহেতু জিসি রান অ-নিরোধক, তাই এটি এক্সেল প্রক্রিয়াটিকে আকাঙ্ক্ষার চেয়ে দীর্ঘ সময়ের জন্য ধরে রাখতে পারে এবং একটি 'মেমরি ফাঁস' এর ছাপ তৈরি করে।

সমাধান

এখন পর্যন্ত একমাত্র সমাধান হ'ল পিআইএ'র ইভেন্ট সরবরাহকারী সিওএম ক্লাসের জন্য এড়ানো এবং আপনার নিজের ইভেন্ট সরবরাহকারী লিখুন যা নির্বিচারে COM অবজেক্টগুলি প্রকাশ করে।

অ্যাপ্লিকেশন ক্লাসের জন্য, এটি অ্যাপেভেন্টস ইন্টারফেস প্রয়োগ করে এবং তারপরে আইকোনেকশনপয়েন্ট কনটেনার ইন্টারফেস ব্যবহার করে এক্সেল দিয়ে প্রয়োগটি নিবন্ধভুক্ত করার মাধ্যমে এটি করা যেতে পারে । অ্যাপ্লিকেশন শ্রেণি (এবং এই ক্ষেত্রে কলব্যাক প্রক্রিয়া ব্যবহার করে সমস্ত সিওএম অবজেক্ট ইভেন্ট প্রকাশ করে) আইকনেকশনপয়েন্ট কনটেনার ইন্টারফেস প্রয়োগ করে।


4

অন্যদের নির্দিষ্ট করেছি, আপনি প্রতি এক্সেল আপনি যে বস্তুটি ব্যবহারের জন্য একটি সুনির্দিষ্ট রেফারেন্স তৈরি, এবং বর্ণনা অনুযায়ী, যে রেফারেন্সে Marshal.ReleaseComObject ফোন করতে হবে এই কিলোবাইট নিবন্ধ । এমনকি একটি ব্যতিক্রম ছুঁড়ে ফেলা হলেও রিলিজকম অবজেক্টকে সর্বদা ডাকা হয় তা নিশ্চিত করার জন্য আপনার চেষ্টা / অবশেষে ব্যবহার করতে হবে। এর পরিবর্তে:

Worksheet sheet = excelApp.Worksheets(1)
... do something with sheet

আপনার মতো কিছু করা দরকার:

Worksheets sheets = null;
Worksheet sheet = null
try
{ 
    sheets = excelApp.Worksheets;
    sheet = sheets(1);
    ...
}
finally
{
    if (sheets != null) Marshal.ReleaseComObject(sheets);
    if (sheet != null) Marshal.ReleaseComObject(sheet);
}

আপনি যদি এক্সেলটি বন্ধ করতে চান তবে অ্যাপ্লিকেশন অবজেক্টটি প্রকাশের আগে আপনাকে অ্যাপ্লিকেশন.কুইটে কল করতে হবে।

আপনি দেখতে পাচ্ছেন যে, আপনি মাঝারিভাবে জটিল কিছু করার চেষ্টা করার সাথে সাথে এটি দ্রুত খুব অতিরঞ্জিত হয়ে যায়। আমি সফলভাবে একটি সহজ র‌্যাপার ক্লাস সহ নেট অ্যাপ্লিকেশনগুলি সফলভাবে বিকাশ করেছি যা এক্সেল অবজেক্ট মডেলের কয়েকটি সাধারণ ম্যানিপুলেশনগুলিকে আবৃত করে (একটি ওয়ার্কবুক খুলুন, একটি রেঞ্জে লিখুন, ওয়ার্কবুকটি সংরক্ষণ করুন / বন্ধ করুন ইত্যাদি)। মোড়কের ক্লাসটি আইডিস্পোজেবল প্রয়োগ করে, মার্শালকে সাবধানতার সাথে প্রয়োগ করে it রিলেজকম -অবজেক্টটি এটি ব্যবহার করে এমন প্রতিটি বস্তুর উপর প্রয়োগ করে এবং বাকী অ্যাপ্লিকেশনটিতে কোনও এক্সেল বস্তু প্রকাশ্যে প্রকাশ করে না।

তবে এই জটিলতা আরও জটিল প্রয়োজনীয়তার জন্য ভালভাবে স্কেল করে না।

এটি নেট নেট সিএম ইন্টারপের একটি বড় ঘাটতি। আরও জটিল পরিস্থিতিগুলির জন্য, আমি ভিবি 6 বা অন্যান্য ব্যবস্থাপনিত ভাষায় একটি অ্যাক্টিভএক্স ডিএলএল লেখার বিষয়ে গুরুত্ব সহকারে বিবেচনা করব যা আপনি অফিসের মতো আউট-প্রোক সিওএম অবজেক্টগুলির সাথে সমস্ত মিথস্ক্রিয়া ডেলিভারি করতে পারবেন। তারপরে আপনি আপনার .NET অ্যাপ্লিকেশন থেকে এই অ্যাকটিভএক্স ডিএলএলটিকে উল্লেখ করতে পারেন এবং জিনিসগুলি আরও সহজ হবে কারণ আপনার কেবলমাত্র এই একটি রেফারেন্স প্রকাশ করতে হবে।


3

উপরের সমস্ত জিনিস যখন কাজ না করে তখন এক্সেলকে তার পত্রক বন্ধ করার জন্য কিছু সময় দেওয়ার চেষ্টা করুন:

app.workbooks.Close();
Thread.Sleep(500); // adjust, for me it works at around 300+
app.Quit();

...
FinalReleaseComObject(app);

2
আমি নির্বিচারে অপেক্ষা অপছন্দ করি। তবে +1 কারণ আপনি ওয়ার্কবুকগুলি বন্ধ হওয়ার অপেক্ষার অপেক্ষা রাখে। একটি বিকল্প হ'ল ওয়ার্কবুক সংগ্রহকে একটি লুপে পোল করা এবং লুপের সময়সীমা হিসাবে নির্বিচারে অপেক্ষাটি ব্যবহার করা।
dFlat

3

নিশ্চিত হয়ে নিন যে আপনি এক্সেল সম্পর্কিত সমস্ত বস্তু প্রকাশ করেছেন!

বেশ কয়েকটি উপায়ে চেষ্টা করে কয়েক ঘন্টা কাটিয়েছি। সমস্ত দুর্দান্ত ধারণা কিন্তু আমি শেষ পর্যন্ত আমার ভুলটি পেয়েছি: আপনি যদি সমস্ত বস্তু প্রকাশ না করেন তবে উপরের কোনও উপায়ই আপনাকে আমার ক্ষেত্রে পছন্দ করতে সহায়তা করতে পারে না। নিশ্চিত হয়ে নিন যে আপনি রেঞ্জ ওয়ান সহ সমস্ত বস্তু প্রকাশ করেছেন!

Excel.Range rng = (Excel.Range)worksheet.Cells[1, 1];
worksheet.Paste(rng, false);
releaseObject(rng);

বিকল্পগুলি এখানে একসাথে রয়েছে


খুব ভাল পয়েন্ট! আমি মনে করি যেহেতু আমি অফিস 2007 ব্যবহার করছি আমার পক্ষ থেকে কিছু সাফ-আপ করা হয়েছে। আমি পরামর্শটি আরও উপরে ব্যবহার করেছি তবে আপনি এখানে যেমন পরামর্শ দিয়েছিলেন তেমন ভেরিয়েবলগুলি সংরক্ষণ করে রাখেনি এবং এক্সেল.এক্সই প্রস্থান করবে তবে আমি কেবল ভাগ্যবান হতে পারি এবং আমার যদি আরও কোনও সমস্যা হয় তবে আমি অবশ্যই আমার কোডের এই অংশটি দেখব =)
কুপস

3

COM অবজেক্টগুলি প্রকাশের বিষয়ে একটি দুর্দান্ত নিবন্ধটি 2.5 রিলিজিং COM অবজেক্টস (এমএসডিএন)।

যে পদ্ধতিটি আমি সমর্থন করব তা হ'ল আপনার এক্সেলটি বাতিল করুন n ইন্টার্নপ রেফারেন্সগুলি যদি সেগুলি অ-স্থানীয় ভেরিয়েবল হয়, এবং তারপরে কল করুন GC.Collect()এবং GC.WaitForPendingFinalizers()দুবার। স্থানীয়ভাবে স্কোপযুক্ত ইন্টারপ ভেরিয়েবলগুলি স্বয়ংক্রিয়ভাবে যত্ন নেওয়া হবে।

এটি প্রতিটি COM অবজেক্টের জন্য একটি নাম রেফারেন্স রাখার প্রয়োজনীয়তা সরিয়ে দেয় ।

নিবন্ধ থেকে নেওয়া একটি উদাহরণ এখানে:

public class Test {

    // These instance variables must be nulled or Excel will not quit
    private Excel.Application xl;
    private Excel.Workbook book;

    public void DoSomething()
    {
        xl = new Excel.Application();
        xl.Visible = true;
        book = xl.Workbooks.Add(Type.Missing);

        // These variables are locally scoped, so we need not worry about them.
        // Notice I don't care about using two dots.
        Excel.Range rng = book.Worksheets[1].UsedRange;
    }

    public void CleanUp()
    {
        book = null;
        xl.Quit();
        xl = null;

        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

এই শব্দগুলি নিবন্ধ থেকে সরাসরি:

প্রায় সব পরিস্থিতিতে, আরসিডাব্লু রেফারেন্স বাতিল করে এবং জঞ্জাল সংগ্রহের জন্য বাধ্য করা সঠিকভাবে পরিষ্কার হয়ে যাবে। আপনি যদি জিসি.ওয়েটফরপেন্ডিংফাইনালাইজারদেরও কল করেন তবে আবর্জনা সংগ্রহ আপনি যতটা করতে পারবেন ততটাই নির্দোষ হবে। এটি হ'ল, আপনি ঠিক নিশ্চিত হয়ে উঠবেন যে কখন অবজেক্টটি পরিষ্কার করা হবে Wa দ্বিতীয় কল থেকে ওয়েটফরপেন্ডিংফাইনালাইজারগুলিতে ফিরে আসার সময়। বিকল্প হিসাবে, আপনি মার্শাল ব্যবহার করতে পারেন eরিলেজকম। তবে নোট করুন যে আপনার এই পদ্ধতিটি ব্যবহারের খুব বেশি সম্ভাবনা নেই।


2

দুটি বিন্দু নিয়ম আমার পক্ষে কার্যকর হয়নি। আমার ক্ষেত্রে আমি আমার উত্সগুলি পরিষ্কার করার জন্য একটি পদ্ধতি তৈরি করেছি:

private static void Clean()
{
    workBook.Close();
    Marshall.ReleaseComObject(workBook);
    excel.Quit();
    CG.Collect();
    CG.WaitForPendingFinalizers();
}

2

আমার সমাধান

[DllImport("user32.dll")]
static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);

private void GenerateExcel()
{
    var excel = new Microsoft.Office.Interop.Excel.Application();
    int id;
    // Find the Excel Process Id (ath the end, you kill him
    GetWindowThreadProcessId(excel.Hwnd, out id);
    Process excelProcess = Process.GetProcessById(id);

try
{
    // Your code
}
finally
{
    excel.Quit();

    // Kill him !
    excelProcess.Kill();
}

2

ওয়ার্ড / এক্সেল ইন্টারপ অ্যাপ্লিকেশনগুলি ব্যবহার করে আপনার খুব সতর্ক হওয়া উচিত। সমস্ত সমাধানের চেষ্টা করার পরেও আমাদের প্রচুর "উইনওয়ার্ড" প্রক্রিয়াটি সার্ভারে খোলা রয়েছে (২০০০ এর বেশি ব্যবহারকারীদের সাথে)।

ঘন্টাখানেক সমস্যা নিয়ে কাজ করার পরে, আমি বুঝতে পেরেছি যে আমি যদি এক Word.ApplicationClass.Document.Open()সাথে বিভিন্ন থ্রেডে একসাথে একাধিক ডকুমেন্ট খুলি তবে আইআইএস কর্মী প্রক্রিয়া (w3wp.exe) সমস্ত উইনওয়ার্ড প্রক্রিয়া খোলা রেখে ক্র্যাশ হয়ে যাবে!

সুতরাং আমার ধারণা এই সমস্যার কোনও নিখুঁত সমাধান নেই, তবে অফিস ওপেন এক্সএমএল বিকাশের মতো অন্যান্য পদ্ধতিতে স্যুইচ করা ।


1

গৃহীত উত্তরটি আমার পক্ষে কার্যকর হয়নি। ডেস্ট্রাক্টরে নিম্নলিখিত কোডটি কাজটি করেছে।

if (xlApp != null)
{
    xlApp.Workbooks.Close();
    xlApp.Quit();
}

System.Diagnostics.Process[] processArray = System.Diagnostics.Process.GetProcessesByName("EXCEL");
foreach (System.Diagnostics.Process process in processArray)
{
    if (process.MainWindowTitle.Length == 0) { process.Kill(); }
}


1

আমি বর্তমানে অফিস অটোমেশনে কাজ করছি এবং এটির জন্য এমন একটি সমাধান পেয়েছি যা প্রতিবারের জন্য কার্যকর every এটি সহজ এবং কোনও প্রক্রিয়া হত্যার সাথে জড়িত না।

দেখে মনে হচ্ছে যে কেবলমাত্র বর্তমান সক্রিয় প্রক্রিয়াগুলি লুপ করেই এবং কোনও উপায়ে একটি উন্মুক্ত এক্সেল প্রক্রিয়াটি 'অ্যাক্সেস' করার মাধ্যমে এক্সেলের কোনও বিভ্রান্তিকর ঝুলন্ত ঘটনা মুছে ফেলা হবে। নীচের কোডটি কেবল প্রসেসগুলির জন্য যাচাই করে যেখানে নামটি 'এক্সেল', তারপরে প্রক্রিয়াটির মেইন উইন্ডো টাইটেল সম্পত্তিটিকে একটি স্ট্রিংয়ে লিখে দেয়। প্রক্রিয়াটির সাথে এই 'মিথস্ক্রিয়া' উইন্ডোজকে এক্সেলের হিমায়িত দৃষ্টান্তটি বন্ধ এবং বাতিল করতে বলে মনে হচ্ছে।

আমি যে অ্যাড-ইনটি ছাড়ার বিকাশ করছি তার ঠিক আগে আমি নীচের পদ্ধতিটি চালিত করি, কারণ এটি আনলোডিং ইভেন্টটিকে আগুন জ্বলিয়ে দেয়। এটি প্রতিবার এক্সেলের কোনও ঝুলন্ত দৃষ্টান্ত সরিয়ে দেয়। সমস্ত সততার সাথে আমি কেন পুরোপুরি নিশ্চিত নই তবে এটি আমার পক্ষে ভাল কাজ করে এবং ডাবল ডটস, মার্শাল.রিলিজকম, অবজেক্ট বা হত্যা প্রক্রিয়া সম্পর্কে চিন্তা না করে কোনও এক্সেল অ্যাপ্লিকেশন শেষে রেখে দেওয়া যেতে পারে। কেন এটি কার্যকর তা সম্পর্কে আমি যে কোনও পরামর্শে খুব আগ্রহী হব।

public static void SweepExcelProcesses()
{           
            if (Process.GetProcessesByName("EXCEL").Length != 0)
            {
                Process[] processes = Process.GetProcesses();
                foreach (Process process in processes)
                {
                    if (process.ProcessName.ToString() == "excel")
                    {                           
                        string title = process.MainWindowTitle;
                    }
                }
            }
}

1

আমি মনে করি যে এর মধ্যে কিছু উপায় ফ্রেমওয়ার্কটি অফিস অ্যাপ্লিকেশনগুলি পরিচালনা করে তবে আমি ভুল হতে পারি। কিছু দিন, কিছু অ্যাপ্লিকেশনগুলি তত্ক্ষণাত্ প্রক্রিয়াগুলি পরিষ্কার করে দেয় এবং অন্যান্য দিনগুলি অ্যাপ্লিকেশনটি বন্ধ না হওয়া পর্যন্ত অপেক্ষা করা হবে বলে মনে হয়। সাধারণভাবে, আমি বিশদটির প্রতি মনোযোগ দেওয়া ছেড়ে দিয়েছি এবং কেবলমাত্র নিশ্চিত হয়ে নিন যে দিনের শেষে কোনও অতিরিক্ত প্রক্রিয়া ভেসে উঠছে না।

এছাড়াও, এবং সম্ভবত আমি জিনিসগুলি সরল করার চেয়েও বেশি করছি তবে আমি মনে করি আপনি কেবল ...

objExcel = new Excel.Application();
objBook = (Excel.Workbook)(objExcel.Workbooks.Add(Type.Missing));
DoSomeStuff(objBook);
SaveTheBook(objBook);
objBook.Close(false, Type.Missing, Type.Missing);
objExcel.Quit();

আমি আগে যেমন বলেছিলাম, এক্সেল প্রক্রিয়াটি কখন প্রদর্শিত হবে বা অদৃশ্য হবে তার বিবরণে আমি মনোযোগ দেওয়ার প্রবণতা রাখি না, তবে এটি সাধারণত আমার পক্ষে কাজ করে। আমি ন্যূনতম সময় ব্যতীত অন্য যে কোনও জন্য এক্সেল প্রসেসগুলি ঘিরে রাখতে পছন্দ করি না তবে আমি সম্ভবত এটির জন্য ব্যর্থ হয়ে যাচ্ছি।


1

কিছু সম্ভবত ইতিমধ্যে লিখেছেন, আপনি কীভাবে এক্সেল (অবজেক্ট) বন্ধ করবেন তা কেবল গুরুত্বপূর্ণ নয় ; আপনি কীভাবে এটি খোলেন তাও গুরুত্বপূর্ণ এবং প্রকল্পের ধরণের দ্বারাও এটি গুরুত্বপূর্ণ ।

ডাব্লুপিএফ অ্যাপ্লিকেশনটিতে মূলত একই কোডটি খুব কম সমস্যা ছাড়াই বা কাজ করছে।

আমার একটি প্রকল্প রয়েছে যাতে একই এক্সেল ফাইলটি বিভিন্ন প্যারামিটার মানের জন্য একাধিকবার প্রক্রিয়াজাত করা হয় - যেমন জেনেরিক তালিকার অভ্যন্তরের মানগুলির ভিত্তিতে পার্স করা p

আমি এক্সেল সম্পর্কিত সমস্ত ফাংশন বেস ক্লাসে রেখেছি এবং একটি সাবক্লাসে পার্সার করি (বিভিন্ন পার্সার সাধারণ এক্সেল ফাংশন ব্যবহার করে)। আমি চাইনি যে জেনেরিক তালিকার প্রতিটি আইটেমের জন্য এক্সেল খোলা এবং আবার বন্ধ হয়ে গেছে, তাই আমি এটি কেবল বেস ক্লাসে একবার খুলেছি এবং এটি সাবক্লাসে বন্ধ করে দিয়েছি। কোডটি একটি ডেস্কটপ অ্যাপ্লিকেশনে সরানোর সময় আমার সমস্যা হয়েছিল। আমি উল্লিখিত অনেকগুলি সমাধান চেষ্টা করেছি।GC.Collect()এর আগে দু'বার প্রস্তাবিত হিসাবে ইতিমধ্যে কার্যকর করা হয়েছিল।

তারপরে আমি সিদ্ধান্ত নিয়েছি যে আমি এক্সেল খোলার কোডটি একটি সাবক্লাসে স্থানান্তর করব। কেবল একবার খোলার পরিবর্তে, এখন আমি একটি নতুন অবজেক্ট (বেস ক্লাস) তৈরি করেছি এবং প্রতিটি আইটেমের জন্য এক্সেল খুলছি এবং শেষে এটি বন্ধ করব। এখানে কিছু পারফরম্যান্স পেনাল্টি রয়েছে, তবে বেশ কয়েকটি পরীক্ষার ভিত্তিতে এক্সেল প্রক্রিয়াগুলি সমস্যা ছাড়াই বন্ধ হচ্ছে (ডিবাগ মোডে), তাই অস্থায়ী ফাইলগুলিও সরানো হবে। আমি পরীক্ষা চালিয়ে যাব এবং কিছু আপডেট লিখলে আরও কিছু লিখব।

নীচের লাইনটি হ'ল: আপনার অবশ্যই প্রাথমিক কোডটি পরীক্ষা করতে হবে, বিশেষত আপনার অনেকগুলি ক্লাস ইত্যাদি রয়েছে,

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.