डेटा एक्सेस के बाद C # में एक्सेल एप्लीकेशन प्रोसेस को बंद करना


86

मैं C # में एक एप्लिकेशन लिख रहा हूं जो पढ़ने / लिखने के संचालन के लिए एक एक्सेल टेम्पलेट फ़ाइल खोलता है। मैं चाहता हूं कि जब उपयोगकर्ता एप्लिकेशन को बंद कर दे, तो एक्सेल एप्लिकेशन प्रोसेस को बंद कर दिया गया है, बिना एक्सेल फाइल को सेव किए। ऐप के कई रन के बाद मेरा टास्क मैनेजर देखें।

यहाँ छवि विवरण दर्ज करें

मैं एक्सेल फ़ाइल खोलने के लिए इस कोड का उपयोग करता हूं:

public Excel.Application excelApp = new Excel.Application();
public Excel.Workbook excelBook;
excelBook = excelApp.Workbooks.Add(@"C:/pape.xltx");

और डेटा एक्सेस के लिए मैं इस कोड का उपयोग करता हूं:

Excel.Worksheet excelSheet = (Worksheet)(excelBook.Worksheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;

मुझे स्टैकओवरफ़्लो में इसी तरह के सवाल मिलते हैं जैसे कि यह प्रश्न और यह , और उत्तर का परीक्षण करते हैं, लेकिन यह काम नहीं करता है।


एक्सेल और वर्ड बहुत धीमे हैं और एक टन के साथ आते हैं जैसे आप पर ठोकर खाई है। फ़ाइलें वहाँ कुछ XML और अन्य सामग्री के साथ ज़िप फ़ाइलें हैं। ओपन एक्सएमएल एसडीके (या शायद कुछ और हाल ही में) है जो दस्तावेजों को खोल सकता है। ऐसा कोड स्थानीय रूप से स्थापित कार्यालय के बिना भी काम करता है। Excel का उपयोग न करने पर विचार करें
Sten Petrov

जवाबों:


94

इसे इस्तेमाल करे:

excelBook.Close(0); 
excelApp.Quit();

वर्क-बुक को बंद करते समय, आपके पास तीन वैकल्पिक पैरामीटर हैं:

Workbook.close SaveChanges, filename, routeworkbook 

Workbook.Close(false)या यदि आप देर से बाध्यकारी कर रहे हैं, तो कभी-कभी शून्य का उपयोग करना आसान होता है Workbook.Close(0) यही कारण है कि मैंने इसे कार्यपुस्तिकाओं के समापन को स्वचालित करते समय किया है।

इसके अलावा, मैंने जाकर इसके लिए प्रलेखन को देखा, और इसे यहाँ पाया: एक्सेल वर्कबुक क्लोज़

धन्यवाद,


धन्यवाद प्रिय माइकल, यह ठीक से काम कर रहा है: excelBook.Close (0)
Yousefi

हाय दोस्तों जब आप पढ़ने के लिए एक्सेल फाइल खोल रहे हैं तो यह काम नहीं कर रहा है। निम्नलिखित कोड var excelApp = नया अनुप्रयोग () है; var वर्कबुक = excelApp.Workbooks.Open @ "c: \ temp \ myexcel.xlsx"); workBooks.Close (0); excelApp.Quit ();
user1131926 10

मैंने ApplicationClass का उपयोग किया है ... और मैंने वस्तुओं को निपटाने के लिए उपरोक्त कोड का उपयोग किया है, लेकिन यह काम नहीं करेगा ...
सिंगारवेलन

3
इन सभी उत्तरों के साथ कई असफल प्रयासों के बाद, मैं इस समाधान के साथ प्रक्रिया आईडी प्राप्त करने के लिए गया था जिसे मैंने खोला और सीधे इसे मार दिया।
अंडरडेकबड

@ सिंहलिंगन: क्या आपने डेविड क्लार्क के जवाब की जाँच की है?
Th

22
xlBook.Save();
xlBook.Close(true);
xlApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

यह कोशिश करो .. यह मेरे लिए काम किया ... आपको प्रक्रिया को रोकने के लिए उस xl एप्लिकेशन ऑब्जेक्ट को रिलीज़ करना चाहिए।


14

Ref: https://stackoverflow.com/a/17367570/132599

इस तरह के रूप में डबल-डॉट-कॉलिंग अभिव्यक्ति का उपयोग करने से बचें

var workbook = excel.Workbooks.Open(/*params*/)

... क्योंकि इस तरह से आप केवल कार्यपुस्तिका के लिए नहीं, बल्कि कार्यपुस्तिका के लिए RCW ऑब्जेक्ट बनाते हैं, और आपको इसे भी जारी करना चाहिए (यदि ऑब्जेक्ट का संदर्भ नहीं रखा गया है तो यह संभव नहीं है)।

इससे मेरे लिए समस्या हल हो गई। आपका कोड बन जाता है:

public Excel.Application excelApp = new Excel.Application();
public Excel.Workbooks workbooks;
public Excel.Workbook excelBook;
workbooks = excelApp.Workbooks;
excelBook = workbooks.Add(@"C:/pape.xltx");

...

Excel.Sheets sheets = excelBook.Worksheets;
Excel.Worksheet excelSheet = (Worksheet)(sheets[1]);
excelSheet.DisplayRightToLeft = true;
Range rng;
rng = excelSheet.get_Range("C2");
rng.Value2 = txtName.Text;

और फिर उन सभी वस्तुओं को छोड़ दें:

System.Runtime.InteropServices.Marshal.ReleaseComObject(rng);
System.Runtime.InteropServices.Marshal.ReleaseComObject(excelSheet);
System.Runtime.InteropServices.Marshal.ReleaseComObject(sheets);
excelBook .Save();
excelBook .Close(true);
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlBook);
System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
excelApp.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);

मैं यह try {} finally {}सुनिश्चित करने के लिए कि सब कुछ जारी हो जाता है, भले ही कुछ गलत हो जाए (क्या संभवतः गलत हो सकता है?) जैसे

public Excel.Application excelApp = null;
public Excel.Workbooks workbooks = null;
...
try
{
    excelApp = new Excel.Application();
    workbooks = excelApp.Workbooks;
    ...
}
finally
{
    ...
    if (workbooks != null) System.Runtime.InteropServices.Marshal.ReleaseComObject(workbooks);
    excelApp.Quit();
    System.Runtime.InteropServices.Marshal.ReleaseComObject(xlApp);
}

2
इसने मेरे लिए काम किया है, कार्यपुस्तिका को एक चर में असाइन करना ताकि इसे साफ किया जा सके। इसके अलावा एक अवलोकन, मेरे पास वेब एप्लिकेशन और कंसोल एप्लिकेशन में एक्सेल ऐप को साफ़ करने के लिए समान कोड था। डबल डॉट से छुटकारा पाने के अपडेट से पहले कोड ने कंसोल ऐप में ठीक काम किया लेकिन जब वेब ऐप में चलाया गया तो यह EXCEL.EXE को स्पष्ट नहीं कर पाया। मुझे यकीन नहीं है कि उन्होंने अलग तरह से व्यवहार क्यों किया, लेकिन डबल डॉट संदर्भ से छुटकारा पाने के लिए इसे वेब ऐप में तय किया।
आयरनहाइड

मेरे लिए काम कर रहा है। मुझे लगता है कि राहत देने के लिए, हमें सभी संबंधित ऑब्जेक्ट को रिलीज़ करना होगा। मुझे सॉलिडवर्क्स कार्यक्रम के बारे में भी यही समस्या थी।
जी.एस.

1
कार्यपुस्तिका को बंद करें, एक्सेल एप्लिकेशन को छोड़ दें, डबल-डॉट-कॉलिंग से बचें, और बनाई गई हर एक COM ऑब्जेक्ट को छोड़ दें। मेरे लिए यही काम किया। जीवन रक्षक उत्तर। धन्यवाद।
सिनान ILYAS

13

इसके बारे में सोचो, यह प्रक्रिया को मारता है:

System.Diagnostics.Process[] process=System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (System.Diagnostics.Process p in process)
{
    if (!string.IsNullOrEmpty(p.ProcessName))
    {
        try
        {
            p.Kill();
        }
        catch { }
    }
}

इसके अलावा, क्या आपने इसे सामान्य रूप से बंद करने की कोशिश की?

myWorkbook.SaveAs(@"C:/pape.xltx", missing, missing, missing, missing, missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, missing, missing, missing, missing, missing);
excelBook.Close(null, null, null);                 // close your workbook
excelApp.Quit();                                   // exit excel application
excel = null;                                      // set to NULL

अपने answer.Your पहले समाधान के लिए धन्यवाद बंद कर देता है सभी खुले एक्सेल files.when मैं 'excelBook.Close', एक्सेल का उपयोग संवाद प्रकट होता है को बचाने, और मैं इसे नहीं चाहते हैं :(
जावद Yousefi

1
मैंने इसे संपादित किया और इसे कोड में सेवर्स को करने के लिए एक लाइन के साथ जोड़ा, जो डायलॉग को कोड से बदल देगा, आशा है कि यह मदद करेगा। :)
मॉरिस मियाओ

1
मैंने इसका उपयोग केवल खुली एक्सेल प्रक्रियाओं के लिए एक प्रारंभिक जांच के साथ किया और आईडी को एक सूची में सहेजा। फिर एक नई एक्सेल प्रक्रिया बनाई, जो संपादन मुझे करना पड़ा और जो आईडी सूची में समाहित नहीं थी, उसे किसी भी एक्सेल प्रक्रिया को बंद कर दिया।
182764125216 21

यह कार्य प्रबंधक से एक्सेल जारी करने का सही तरीका नहीं है। आपको उन सभी ऑब्जेक्ट्स को जारी करना चाहिए जो उन लोगों सहित बनाए गए थे जो कि दृश्य के पीछे बनाए गए थे जैसे कि वर्कबोक।
एह

इस तरह, आप एक्सेल प्रक्रिया को चलाने वाले हर एक को मार देंगे। समस्या यह है कि एक ही समय में एक्सेल का उपयोग करने वाले अन्य उपयोगकर्ता या अनुप्रयोग हो सकते हैं। यदि आप ऐसा करने के इच्छुक हैं तो बस ध्यान रखें।
सिनान ILYAS

5

एक्सेल को मारना हमेशा आसान नहीं होता है; इस लेख को देखें: एक्सेल को मारने के 50 तरीके

यह आलेख Microsoft ( MS Knowlege Base Article) से सबसे अच्छी सलाह लेता है ) एक्सेल को अच्छी तरह से छोड़ने के लिए कैसे प्राप्त किया जाए, लेकिन फिर यदि आवश्यक हो तो प्रक्रिया को मारकर इसके बारे में भी सुनिश्चित करता है। मुझे दूसरा पैराशूट पसंद है।

किसी भी खुली कार्यपुस्तिका को बंद करना सुनिश्चित करें, आवेदन को छोड़ें और xlApp ऑब्जेक्ट को छोड़ दें। अंत में यह देखने के लिए जांचें कि क्या प्रक्रिया अभी भी जीवित है और यदि ऐसा है तो इसे मार दें।

यह आलेख यह भी सुनिश्चित करता है कि हम सभी एक्सेल प्रक्रियाओं को नहीं मारते हैं लेकिन केवल उसी सटीक प्रक्रिया को मारते हैं जो शुरू की गई थी।

विंडो हैंडल से भी प्राप्त करें प्रक्रिया

यहां वह कोड है जो मैं उपयोग करता हूं: (हर बार काम करता है)

Sub UsingExcel()

    'declare process; will be used later to attach the Excel process
    Dim XLProc As Process

    'call the sub that will do some work with Excel
    'calling Excel in a separate routine will ensure that it is 
    'out of scope when calling GC.Collect
    'this works better especially in debug mode
    DoOfficeWork(XLProc)

    'Do garbage collection to release the COM pointers
    'http://support.microsoft.com/kb/317109
    GC.Collect()
    GC.WaitForPendingFinalizers()

    'I prefer to have two parachutes when dealing with the Excel process
    'this is the last answer if garbage collection were to fail
    If Not XLProc Is Nothing AndAlso Not XLProc.HasExited Then
        XLProc.Kill()
    End If

End Sub

'http://msdn.microsoft.com/en-us/library/ms633522%28v=vs.85%29.aspx
<System.Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
    Private Shared Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, _
    ByRef lpdwProcessId As Integer) As Integer
End Function

Private Sub ExcelWork(ByRef XLProc As Process)

    'start the application using late binding
    Dim xlApp As Object = CreateObject("Excel.Application")

    'or use early binding
    'Dim xlApp As Microsoft.Office.Interop.Excel

    'get the window handle
    Dim xlHWND As Integer = xlApp.hwnd

    'this will have the process ID after call to GetWindowThreadProcessId
    Dim ProcIdXL As Integer = 0

    'get the process ID
    GetWindowThreadProcessId(xlHWND, ProcIdXL)

    'get the process
    XLProc = Process.GetProcessById(ProcIdXL)


    'do some work with Excel here using xlApp

    'be sure to save and close all workbooks when done

    'release all objects used (except xlApp) using NAR(x)


    'Quit Excel 
    xlApp.quit()

    'Release
    NAR(xlApp)

End Sub

Private Sub NAR(ByVal o As Object)
    'http://support.microsoft.com/kb/317109
    Try
        While (System.Runtime.InteropServices.Marshal.ReleaseComObject(o) > 0)
        End While
    Catch
    Finally
        o = Nothing
    End Try
End Sub

यह एकमात्र समाधान था जिसने मेरे लिए काम किया। धन्यवाद।
जॉन वोट

2

मैं एक ही समस्याओं से मिला और इसे हल करने के लिए कई तरीके आजमाए लेकिन काम नहीं किया। अंत में, मैं अपने रास्ते से मिला। कुछ संदर्भ यहां लिंक विवरण दर्ज करते हैं

आशा है कि मेरा कोड भविष्य में किसी की मदद कर सकता है। मुझे इसे हल करने में दो दिन से अधिक का समय लगा है। नीचे मेरा कोड है:

//get current in useing excel
            Process[] excelProcsOld = Process.GetProcessesByName("EXCEL");
            Excel.Application myExcelApp = null;
            Excel.Workbooks excelWorkbookTemplate = null;
            Excel.Workbook excelWorkbook = null;
try{
    //DO sth using myExcelApp , excelWorkbookTemplate, excelWorkbook
}
catch (Exception ex ){
}
finally
            {
                //Compare the EXCEL ID and Kill it 
                Process[] excelProcsNew = Process.GetProcessesByName("EXCEL");
                foreach (Process procNew in excelProcsNew)
                {
                    int exist = 0;
                    foreach (Process procOld in excelProcsOld)
                    {
                        if (procNew.Id == procOld.Id)
                        {
                            exist++;
                        }
                    }
                    if (exist == 0)
                    {
                        procNew.Kill();
                    }        
                }
            }

1

excelBook.Close (); excelApp.Quit (); कोड का अंत जोड़ें, यह पर्याप्त हो सकता है। यह मेरे कोड पर काम कर रहा है


हां, लेकिन जब मैं इसका उपयोग करता हूं, तो डायलॉग सेव दिखाई देता है, और मैं नहीं चाहता कि यह दिखाई दे:
जावेद युसेफी

1

आप अपनी खुद की COMवस्तु एक्सेल पिड के साथ प्रक्रिया को मार सकते हैं

dll आयात कोड के नीचे कहीं जोड़ें

[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);

और उपयोग करें

 if (excelApp != null)
            {
                int excelProcessId = -1;
                GetWindowThreadProcessId(new IntPtr(excelApp.Hwnd), ref excelProcessId);

                Process ExcelProc = Process.GetProcessById(excelProcessId);
                if (ExcelProc != null)
                {
                    ExcelProc.Kill();
                }
            }

1

मैंने पाया है कि लूप के Marshal.ReleaseComObjectभीतर होना Whileऔर गारबेज कलेक्शन के साथ खत्म होना महत्वपूर्ण है ।

static void Main(string[] args)
{
    Excel.Application xApp = new Excel.Application();
    Excel.Workbooks xWbs = xApp.Workbooks;
    Excel.Workbook xWb = xWbs.Open("file.xlsx");

    Console.WriteLine(xWb.Sheets.Count);

    xWb.Close();
    xApp.Quit();

    while (Marshal.ReleaseComObject(xWb) != 0);
    while (Marshal.ReleaseComObject(xWbs) != 0);
    while (Marshal.ReleaseComObject(xApp) != 0);

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

0
         wb.Close();
         app.Quit();

         System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
         foreach (System.Diagnostics.Process p in process)
         {
             if (!string.IsNullOrEmpty(p.ProcessName) && p.StartTime.AddSeconds(+10) > DateTime.Now)
             {
                 try
                 {
                     p.Kill();
                 }
                 catch { }
             }
         }

यह "एक्सेल" नाम के साथ अंतिम 10 सेकंड की प्रक्रिया बंद करता है


0

सभी एक्सेल प्रक्रिया को बंद करने का सही तरीका

var _excel = new Application();
foreach (Workbook _workbook in _excel.Workbooks) {
    _workbook.Close(0);
}

_excel.Quit();
_excel = null;
var process = System.Diagnostics.Process.GetProcessesByName("Excel");
foreach (var p in process) {
    if (!string.IsNullOrEmpty(p.ProcessName)) {
        try {
            p.Kill();
        } catch { }
    }
}

0

एक और उपाय पर आधारित है। मेरे पास इसका उपयोग है:

IntPtr xAsIntPtr = new IntPtr(excelObj.Application.Hwnd);
excelObj.ActiveWorkbook.Close();

System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
                foreach (System.Diagnostics.Process p in process)
                {
                    if (p.MainWindowHandle == xAsIntPtr)
                    {
                        try
                        {
                            p.Kill();
                        }
                        catch { }
                    }
                }

प्रक्रिया की पहचान करने और उसे बंद करने के लिए "MainWindowHandle" का उपयोग करना।

excelObj: यह मेरा एप्लीकेशन इंटरोप एक्सेल ऑब्जेक्ट है


0

प्रत्येक एक्सेल ऑब्जेक्ट के लिए एक वैरिएबल का उपयोग करें और लूप अवश्य करें Marshal.ReleaseComObject >0। लूप के बिना, एक्सेल प्रक्रिया अभी भी सक्रिय रहती है।

public class test{
        private dynamic ExcelObject;
        protected dynamic ExcelBook;
        protected dynamic ExcelBooks;
        protected dynamic ExcelSheet;

public void LoadExcel(string FileName)
        {
            Type t = Type.GetTypeFromProgID("Excel.Application");
            if (t == null) throw new Exception("Excel non installato");
            ExcelObject = System.Activator.CreateInstance(t);
            ExcelObject.Visible = false;
            ExcelObject.DisplayAlerts = false;
            ExcelObject.AskToUpdateLinks = false;
            ExcelBooks = ExcelObject.Workbooks;
            ExcelBook = ExcelBooks.Open(FileName,0,true);
            System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
            ExcelSheet = ExcelBook.Sheets[1];
        }
 private void ReleaseObj(object obj)
        {
            try
            {
                int i = 0;
             while(   System.Runtime.InteropServices.Marshal.ReleaseComObject(obj) > 0)
                {
                    i++;
                    if (i > 1000) break;
                }
                obj = null;
            }
            catch 
            {
                obj = null;
            }
            finally
            {
                GC.Collect();
            }
        }
        public void ChiudiExcel() {
            System.Threading.Thread.CurrentThread.CurrentCulture = ci;

            ReleaseObj(ExcelSheet);
            try { ExcelBook.Close(); } catch { }
            try { ExcelBooks.Close(); } catch { }
            ReleaseObj(ExcelBooks);
            try { ExcelObject.Quit(); } catch { }
            ReleaseObj(ExcelObject);
        }
}

0

निम्नलिखित कोड का उपयोग करके xls को xlsx में परिवर्तित करते हुए हम एक्सेल एप्लीकेशन को बंद कर सकते हैं। जब हम इस तरह का कार्य करते हैं तो एक्सेल एप्लिकेशन टास्क मैनेजर में चल रहा होता है, हमें इस एक्सेल को बंद करना चाहिए जो बैकग्राउंड में चल रहा है। इंटरॉप एक कॉम घटक है, जिस कॉम घटक का उपयोग करने के लिए हमने मार्शल का उपयोग किया है। FinalReleaseComObject।

 private void button1_Click(object sender, EventArgs e)
    {

        Excel03to07("D:\\TestExls\\TestExcelApp.XLS");

    }
    private void Excel03to07(string fileName)
    {
        string svfileName = Path.ChangeExtension(fileName, ".xlsx");
        object oMissing = Type.Missing;
        var app = new Microsoft.Office.Interop.Excel.Application();
        var wb = app.Workbooks.Open(fileName, oMissing, oMissing,
                        oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing, oMissing);
        wb.SaveAs(svfileName, XlFileFormat.xlOpenXMLWorkbook, Type.Missing, Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlNoChange, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

        wb.Close(false, Type.Missing, Type.Missing);
        app.Quit();
        GC.Collect();
        Marshal.FinalReleaseComObject(wb);
        Marshal.FinalReleaseComObject(app);
   }

0

अधिकांश विधियाँ काम करती हैं, लेकिन एक्सेल प्रक्रिया हमेशा तब तक रहती है जब तक कि वे तालियाँ बन्द न कर दें।

जब एक बार एक्सेल प्रक्रिया को मार दिया जाता है तो उसे एक ही धागे में एक बार फिर से निष्पादित नहीं किया जा सकता है - पता नहीं क्यों।


-1
        GetWindowThreadProcessId((IntPtr)app.Hwnd, out iProcessId);
        wb.Close(true,Missing.Value,Missing.Value);
        app.Quit();
        System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("Excel");
        foreach (System.Diagnostics.Process p in process)
        {
            if (p.Id == iProcessId)
            {
                try
                {
                    p.Kill();
                }
                catch { }
            }
        }
}
[DllImport("user32.dll")]

private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

uint iProcessId = 0;

यह GetWindowThreadProcessId सही प्रक्रिया Id o excell पाता है .... इसे मारने के बाद .... इसका आनंद लें !!!


-1
private void releaseObject(object obj)
{
    try
    {
        System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
        obj = null;
    }
    catch (Exception ex)
    {
        obj = null;
        MessageBox.Show("Unable to release the Object " + ex.ToString());
    }
    finally
    {
        GC.Collect();
    }
}

हालांकि यह कोड प्रश्न को हल कर सकता है, जिसमें यह भी बताया गया है कि यह समस्या कैसे और क्यों हल करती है, इससे वास्तव में आपके पोस्ट की गुणवत्ता को बेहतर बनाने में मदद मिलेगी, और शायद अधिक वोट भी मिलेंगे। याद रखें कि आप भविष्य में पाठकों के लिए सवाल का जवाब दे रहे हैं, न कि केवल उस व्यक्ति से जो अब पूछ रहा है। कृपया स्पष्टीकरण जोड़ने के लिए अपने उत्तर को संपादित करें, और इस बात का संकेत दें कि क्या सीमाएँ और मान्यताएँ लागू होती हैं।
डेव
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.