Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일

C#에서 만든 COM 객체를 C/C++로 P/Invoke Interop 시 메모리 누수(Memory Leak) 발생

닷넷 객체를 COM 방식으로 접근할 수 있도록 다음과 같이 만들 수 있습니다.

[ComVisible(true)]
[Guid("34CF251B-EAED-428D-9686-C5A5711D3A3E")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IMyUnk
{
    void Test();
}

[ComVisible(true)]
[Guid("c9f685ea-3388-3ff5-958a-3234d08587c1")]
[ClassInterface(ClassInterfaceType.None)]
public class MyUnkObject : IMyUnk
{
    public void Test()
    {
        // Console.WriteLine("Call: Test()");
    }
}

그럼 C++에서 이런 식으로 함수를 정의하면,

extern "C"
{
    interface IMyUnk : IUnknown
    {
    public:
        virtual HRESULT STDMETHODCALLTYPE Test() = 0;
    };

    __declspec(dllexport) void __cdecl UseIUnk(IUnknown *pUnk, bool doRelease)
    {
        if (pUnk == nullptr)
        {
            return;
        }

        IID iid;
        IIDFromString(L"{34CF251B-EAED-428D-9686-C5A5711D3A3E}", &iid);
        
        IMyUnk* myPtr = nullptr;
        if (pUnk->QueryInterface(iid, (LPVOID*)&myPtr) != S_OK)
        {
            return;
        }

        myPtr->Test();
        myPtr->Release();

        if (doRelease == true)
        {
            pUnk->Release();
        }
    }
}

C#에서 C++로 MyObject 객체를 다음과 같이 전달해 사용할 수 있습니다.

using DetourFunc.ClrType;
using System;
using System.Runtime.InteropServices;

namespace ConsoleApp1
{
    class Program
    {
        [DllImport("IUnkSample.dll")]
        internal static unsafe extern void UseIUnk([MarshalAs(UnmanagedType.Interface)] object unk, bool doRelease);

        static void Main(string[] args)
        {
            MyObject obj = new MyObject();
            UseIUnk(obj, true);
        }
    }
}




문제는 저렇게 interop을 하는 경우 메모리 누수가 발생한다는 겁니다. 실제로 아래와 같이 실행해 보면,

static void Main(string[] args)
{
    int i = 0;
    while (true)
    {
        TestHandleLeak();

        i++;

        if (i > 1000)
        {
            GC.Collect();
            GC.Collect();
            i = 0;
        }
    }
}

private unsafe static void TestHandleLeak()
{
    MyUnkObject obj = new MyUnkObject();
    UseIUnk(obj, true);
}

메모리가 증가하는 것을 확인할 수 있습니다. 얼핏 보면 이번에도 이전에 설명했던 것들과 비슷한 상황인 듯한데,

C# - Marshal.GetNativeVariantForObject 사용 시 메모리 누수(Memory Leak) 발생 및 해결 방법
; https://www.sysnet.pe.kr/2/0/12157

C# - Marshal.GetIUnknownForObject/GetIDispatchForObject 사용 시 메모리 누수(Memory Leak) 발생
; https://www.sysnet.pe.kr/2/0/12158

근본적인 원인은 다른 것 같습니다. 왜냐하면, !gchandles의 "Ref Count Handles"가 증가하지 않고 순수하게 닷넷 객체가 해제되지 않아 쌓이기 때문입니다. 게다가 C++ 측에서 VARIANT로 받아 VariantClear를 호출하는 식의 방법도,

// C++
__declspec(dllexport) void __cdecl UseObjectToVariant(VARIANT variant)
{
    VariantClear(&variant);
}


// C#
[DllImport("IUnkSample.dll")]
internal static unsafe extern void UseObjectToVariant(object variant);

private unsafe static void TestHandleLeak2()
{
    // object obj = new object();
    MyUnkObject obj = new MyUnkObject();
    UseObjectToVariant(obj);
            
    // UseObjectToVariant(5.5); // VARIANT의 데이터 필드에 저장할 수 있는 데이터는 메모리 누수가 없음
}

이번에는 해결책이 되지 못했습니다.




문제 유형은 다르지만, 그래도 해결 방식은 "C# - Marshal.GetIUnknownForObject/GetIDispatchForObject 사용 시 메모리 누수(Memory Leak) 발생" 글과 마찬가지로 다룰 수 있습니다.

해당 글에서 만든 (ObjectInterface 타입을 이름 변경한) VariantMarshaller 타입을 정리해 DetourFunc 라이브러리에 넣어 두었으니 NuGet을 통해,

Install-Package DetourFunc -Version 1.1.1

// 소스 코드: github - https://github.com/stjeong/DotNetSamples/tree/master/WinConsole/PEFormat/DetourFunc

참조 추가하면 다음과 같이 사용할 수 있습니다.

[DllImport("IUnkSample.dll")]
internal static unsafe extern void UseIntPtrToVariant(IntPtr variant);

private unsafe static void TestHandleWithoutLeak()
{
    MyUnkObject obj = new MyUnkObject();

    using (VariantMarshaller oi = new VariantMarshaller(obj))
    {
        UseIntPtrToVariant(oi.Variant);
    }
}

그리고 대응하는 C++ 함수에서는 그냥 사용만 하면 됩니다. (이후 실행해 확인하면 메모리 누수가 발생하지 않습니다.)

__declspec(dllexport) void __cdecl UseIntPtrToVariant(VARIANT *variant)
{
    // variant->punkVal // (IUnknown *)
}




그런데, 이런 식의 메모리 누수가 현실적으로 문제로 인식되는 경우는 많지 않습니다. 왜냐하면, .NET 객체를 COM 인터페이스로 Native에 넘기는 경우도 많지 않을 뿐더러, 그렇다고 해도 웬만큼 반복하지 않는 한 메모리 누수가 크게 부각되기까지는 꽤나 시간이 걸릴 것이기 때문입니다.

게다가 그 문제를 완화시키는 또 다른 사유로는, 이런 문제가 (Managed COM 객체가 아닌) Native COM 객체를 pinvoke로 전달할 때는 발생하지 않는다는 점입니다. 예를 들어, 아래의 코드는 메모리 누수가 발생하지 않습니다.

private unsafe static void TestHandleWithXmlDoc()
{
    Type type = Type.GetTypeFromProgID("Microsoft.XMLDOM");

    object xmlDoc = Activator.CreateInstance(type); // native COM 객체 생성
    UseIUnk(xmlDoc, false);
}

(첨부 파일은 이 글의 예제 코드를 포함합니다.)




참고로, pinvoke에서 object 인자의 마샬링 과정을 살펴보면 최초 UseIUnk 호출 시,

C:\ConsoleApp1\ConsoleApp1\Program.cs @ 47:
00007ffc`7cf40985 488b4df0        mov     rcx,qword ptr [rbp-10h]
00007ffc`7cf40989 e802fbffff      call    00007ffc`7cf40490 (ConsoleApp1.Program.UseIUnk(System.Object), mdToken: 0000000006000001)
00007ffc`7cf4098e 90              nop

마샬링을 위한 코드가 JIT 컴파일되는 과정을 동일하게 거쳐,

00007ffc`7cf40490 49ba005ae37cfc7f0000 mov r10,7FFC7CE35A00h
00007ffc`7cf4049a 40e96043545f    jmp     clr!ThePreStub (00007ffc`dc484800)

clr!ThePreStub:
00007ffc`dc484800 4157            push    r15
00007ffc`dc484802 4156            push    r14
00007ffc`dc484804 4155            push    r13
00007ffc`dc484806 4154            push    r12
00007ffc`dc484808 55              push    rbp
00007ffc`dc484809 53              push    rbx
00007ffc`dc48480a 56              push    rsi
00007ffc`dc48480b 57              push    rdi
00007ffc`dc48480c 4883ec68        sub     rsp,68h
00007ffc`dc484810 48898c24b0000000 mov     qword ptr [rsp+0B0h],rcx
00007ffc`dc484818 48899424b8000000 mov     qword ptr [rsp+0B8h],rdx
00007ffc`dc484820 4c898424c0000000 mov     qword ptr [rsp+0C0h],r8
00007ffc`dc484828 4c898c24c8000000 mov     qword ptr [rsp+0C8h],r9
00007ffc`dc484830 660f7f442420    movdqa  xmmword ptr [rsp+20h],xmm0
00007ffc`dc484836 660f7f4c2430    movdqa  xmmword ptr [rsp+30h],xmm1
00007ffc`dc48483c 660f7f542440    movdqa  xmmword ptr [rsp+40h],xmm2
00007ffc`dc484842 660f7f5c2450    movdqa  xmmword ptr [rsp+50h],xmm3
00007ffc`dc484848 488d4c2468      lea     rcx,[rsp+68h]
00007ffc`dc48484d 498bd2          mov     rdx,r10
00007ffc`dc484850 e8eba30000      call    clr!PreStubWorker (00007ffc`dc48ec40)
00007ffc`dc484855 660f6f442420    movdqa  xmm0,xmmword ptr [rsp+20h]
00007ffc`dc48485b 660f6f4c2430    movdqa  xmm1,xmmword ptr [rsp+30h]
00007ffc`dc484861 660f6f542440    movdqa  xmm2,xmmword ptr [rsp+40h]
00007ffc`dc484867 660f6f5c2450    movdqa  xmm3,xmmword ptr [rsp+50h]
00007ffc`dc48486d 488b8c24b0000000 mov     rcx,qword ptr [rsp+0B0h]
00007ffc`dc484875 488b9424b8000000 mov     rdx,qword ptr [rsp+0B8h]
00007ffc`dc48487d 4c8b8424c0000000 mov     r8,qword ptr [rsp+0C0h]
00007ffc`dc484885 4c8b8c24c8000000 mov     r9,qword ptr [rsp+0C8h]
00007ffc`dc48488d 4883c468        add     rsp,68h
00007ffc`dc484891 5f              pop     rdi
00007ffc`dc484892 5e              pop     rsi
00007ffc`dc484893 5b              pop     rbx
00007ffc`dc484894 5d              pop     rbp
00007ffc`dc484895 415c            pop     r12
00007ffc`dc484897 415d            pop     r13
00007ffc`dc484899 415e            pop     r14
00007ffc`dc48489b 415f            pop     r15
00007ffc`dc48489d 48ffe0          jmp     rax  // JIT 컴파일 시켜 jmp 코드로 바뀐 원래의 호출 위치로 다시 JMP (rax == 00007ffc`7cf40490)

00007ffc`7cf40490 49ba005ae37cfc7f0000 mov r10,7FFC7CE35A00h
00007ffc`7cf4049a 40e910050000    jmp     00007ffc`7cf409b0  // Jit된 대상 메서드로 JMP

PInvoke 층의 메서드 내에서 InterfaceMarshaler__ConvertToNative 함수를 통해 "object" 인자를 native로 전달하기 위한 마샬링 작업을 수행합니다.

00007ffc`7cf409b0 55              push    rbp
00007ffc`7cf409b1 4157            push    r15
00007ffc`7cf409b3 4156            push    r14
00007ffc`7cf409b5 4155            push    r13
00007ffc`7cf409b7 4154            push    r12
00007ffc`7cf409b9 57              push    rdi
00007ffc`7cf409ba 56              push    rsi
00007ffc`7cf409bb 53              push    rbx
00007ffc`7cf409bc 4881ec98000000  sub     rsp,98h
00007ffc`7cf409c3 488dac24d0000000 lea     rbp,[rsp+0D0h]
00007ffc`7cf409cb 4c8955a0        mov     qword ptr [rbp-60h],r10
00007ffc`7cf409cf 4889a550ffffff  mov     qword ptr [rbp-0B0h],rsp
00007ffc`7cf409d6 48894d10        mov     qword ptr [rbp+10h],rcx
00007ffc`7cf409da 488d8d68ffffff  lea     rcx,[rbp-98h]
00007ffc`7cf409e1 498bd2          mov     rdx,r10
00007ffc`7cf409e4 e85744545f      call    clr!JIT_InitPInvokeFrame (00007ffc`dc484e40)
00007ffc`7cf409e9 488945a8        mov     qword ptr [rbp-58h],rax
00007ffc`7cf409ed 488bcc          mov     rcx,rsp
00007ffc`7cf409f0 48894d88        mov     qword ptr [rbp-78h],rcx
00007ffc`7cf409f4 488bcd          mov     rcx,rbp
00007ffc`7cf409f7 48894d98        mov     qword ptr [rbp-68h],rcx
00007ffc`7cf409fb 488b4da8        mov     rcx,qword ptr [rbp-58h]
00007ffc`7cf409ff 488d8568ffffff  lea     rax,[rbp-98h]
00007ffc`7cf40a06 48894110        mov     qword ptr [rcx+10h],rax
00007ffc`7cf40a0a 488b4da0        mov     rcx,qword ptr [rbp-60h]
00007ffc`7cf40a0e e87d06685f      call    clr!StubHelpers::DemandPermission (00007ffc`dc5c1090)
00007ffc`7cf40a13 4533c0          xor     r8d,r8d
00007ffc`7cf40a16 448945c4        mov     dword ptr [rbp-3Ch],r8d
00007ffc`7cf40a1a 90              nop
00007ffc`7cf40a1b 4533c0          xor     r8d,r8d
00007ffc`7cf40a1e 4d63c0          movsxd  r8,r8d
00007ffc`7cf40a21 33d2            xor     edx,edx
00007ffc`7cf40a23 4863d2          movsxd  rdx,edx
00007ffc`7cf40a26 488b4d10        mov     rcx,qword ptr [rbp+10h]
00007ffc`7cf40a2a 41b910000000    mov     r9d,10h
00007ffc`7cf40a30 e85b8c625f      call    clr!StubHelpers::InterfaceMarshaler__ConvertToNative (00007ffc`dc569690)
00007ffc`7cf40a35 488945b8        mov     qword ptr [rbp-48h],rax
00007ffc`7cf40a39 c745c401000000  mov     dword ptr [rbp-3Ch],1
00007ffc`7cf40a40 90              nop
00007ffc`7cf40a41 488b4da0        mov     rcx,qword ptr [rbp-60h]
00007ffc`7cf40a45 41bb20000000    mov     r11d,20h
...[생략]...

InterfaceMarshaler__ConvertToNative 호출 시점의 rcx에는 object 인자의 GC Heap 주소가 담겨 있습니다. InterfaceMarshaler__ConvertToNative 함수가 기존의 Marshal.GetIUnknownForObject, Marshal.GetNativeVariantForObject와 다른 점은 내부에서 "clr!MarshalObjectToInterface" 함수를 부른다는 정도입니다.

clr!StubHelpers::InterfaceMarshaler__ConvertToNative:
00007ffc`dc569690 44894c2420      mov     dword ptr [rsp+20h],r9d ss:00000000`003ee7b8=02502df0
00007ffc`dc569695 4c89442418      mov     qword ptr [rsp+18h],r8
00007ffc`dc56969a 4889542410      mov     qword ptr [rsp+10h],rdx
00007ffc`dc56969f 53              push    rbx
00007ffc`dc5696a0 56              push    rsi
00007ffc`dc5696a1 57              push    rdi
00007ffc`dc5696a2 4154            push    r12
00007ffc`dc5696a4 4155            push    r13
00007ffc`dc5696a6 4156            push    r14
00007ffc`dc5696a8 4157            push    r15
00007ffc`dc5696aa 4881ec60010000  sub     rsp,160h
00007ffc`dc5696b1 48c7442458feffffff mov   qword ptr [rsp+58h],0FFFFFFFFFFFFFFFEh
00007ffc`dc5696ba 458bf1          mov     r14d,r9d
00007ffc`dc5696bd 4d8bf8          mov     r15,r8
00007ffc`dc5696c0 4c8be2          mov     r12,rdx
00007ffc`dc5696c3 488d35c6ffffff  lea     rsi,[clr!StubHelpers::InterfaceMarshaler__ConvertToNative (00007ffc`dc569690)]
00007ffc`dc5696ca 4889742438      mov     qword ptr [rsp+38h],rsi
00007ffc`dc5696cf 4885c9          test    rcx,rcx
00007ffc`dc5696d2 0f84d0000000    je      clr!StubHelpers::InterfaceMarshaler__ConvertToNative+0x118 (00007ffc`dc5697a8)
00007ffc`dc5696d8 488364243000    and     qword ptr [rsp+30h],0

00007ffc`dc5696de 48894c2428      mov     qword ptr [rsp+28h],rcx
00007ffc`dc5696e3 c784249000000040000000 mov dword ptr [rsp+90h],40h
00007ffc`dc5696ee 4889b424a0000000 mov     qword ptr [rsp+0A0h],rsi
00007ffc`dc5696f6 488d05fb886e00  lea     rax,[clr!HelperMethodFrame_1OBJ::`vftable' (00007ffc`dcc51ff8)]
00007ffc`dc5696fd 4889442478      mov     qword ptr [rsp+78h],rax
00007ffc`dc569702 488d442428      lea     rax,[rsp+28h]
00007ffc`dc569707 4889842450010000 mov     qword ptr [rsp+150h],rax
00007ffc`dc56970f 488d8c24a8000000 lea     rcx,[rsp+0A8h]
00007ffc`dc569717 e8d4b7f1ff      call    clr!LazyMachStateCaptureState (00007ffc`dc484ef0)
00007ffc`dc56971c 488d4c2478      lea     rcx,[rsp+78h]
00007ffc`dc569721 e80ab8f1ff      call    clr!HelperMethodFrame::Push (00007ffc`dc484f30)
00007ffc`dc569726 488b8c2498000000 mov     rcx,qword ptr [rsp+98h]
00007ffc`dc56972e 33ff            xor     edi,edi
00007ffc`dc569730 4532ed          xor     r13b,r13b
00007ffc`dc569733 8a05ff989200    mov     al,byte ptr [clr!g_StackProbingEnabled (00007ffc`dce93038)]
00007ffc`dc569739 84c0            test    al,al
00007ffc`dc56973b 0f851b3e3000    jne     clr!StubHelpers::InterfaceMarshaler__ConvertToNative+0x303ecc (00007ffc`dc86d55c)

00007ffc`dc569741 458bce          mov     r9d,r14d
00007ffc`dc569744 4d8bc7          mov     r8,r15
00007ffc`dc569747 498bd4          mov     rdx,r12
00007ffc`dc56974a 488d4c2428      lea     rcx,[rsp+28h]
00007ffc`dc56974f e864000000      call    clr!MarshalObjectToInterface (00007ffc`dc5697b8)
00007ffc`dc569754 488bd8          mov     rbx,rax
00007ffc`dc569757 4889442430      mov     qword ptr [rsp+30h],rax
00007ffc`dc56975c c644244800      mov     byte ptr [rsp+48h],0
00007ffc`dc569761 803dd098920000  cmp     byte ptr [clr!g_StackProbingEnabled (00007ffc`dce93038)],0
00007ffc`dc569768 0f85123e3000    jne     clr!StubHelpers::InterfaceMarshaler__ConvertToNative+0x303ef0 (00007ffc`dc86d580)
00007ffc`dc56976e 4584ed          test    r13b,r13b
00007ffc`dc569771 7539            jne     clr!StubHelpers::InterfaceMarshaler__ConvertToNative+0x11c (00007ffc`dc5697ac)
00007ffc`dc569773 488d4c2478      lea     rcx,[rsp+78h]
00007ffc`dc569778 e8f3b7f1ff      call    clr!HelperMethodFrame::Pop (00007ffc`dc484f70)
00007ffc`dc56977d 488d8c24a8000000 lea     rcx,[rsp+0A8h]
00007ffc`dc569785 e846acf1ff      call    clr!HelperMethodFrameRestoreState (00007ffc`dc4843d0)
00007ffc`dc56978a 85c0            test    eax,eax
00007ffc`dc56978c 0f8551ffffff    jne     clr!StubHelpers::InterfaceMarshaler__ConvertToNative+0x53 (00007ffc`dc5696e3)
00007ffc`dc569792 488bc3          mov     rax,rbx
00007ffc`dc569795 4881c460010000  add     rsp,160h
00007ffc`dc56979c 415f            pop     r15
00007ffc`dc56979e 415e            pop     r14
00007ffc`dc5697a0 415d            pop     r13
00007ffc`dc5697a2 415c            pop     r12
00007ffc`dc5697a4 5f              pop     rdi
00007ffc`dc5697a5 5e              pop     rsi
00007ffc`dc5697a6 5b              pop     rbx
00007ffc`dc5697a7 c3              ret

실제로 rcx에 object의 [주소를 가리키는 주솟값]을 담아 MarshalObjectToInterface 호출하고 반환받은 rax값을 살펴보면,

00007ffc`dc56974f e864000000      call    clr!MarshalObjectToInterface (00007ffc`dc5697b8)
                        // 결괏값: rax == 00000000`007c0018

0:000> dq @rax L1
00000000`007c0018 0000000000960938 // IDispatch

IDispatch 인터페이스를 가리키는 포인터가 담겨 있음을 알 수 있습니다.

0:000> dq 0000000000960938 L7
00000000`00960938 00007ffcdc5692f0 00007ffcdc4d7920 00007ffcdc568e50 00007ffcdc9dc1a0
00000000`00960958 00007ffcdc9dc370 00007ffcdc9dbf70 00007ffcdc9dc5b0 

00007ffcdc5692f0부터 00007ffcdc9dc5b0까지의 7개 주소는 IDispatch의 정의 따라 각각 다음의 함수 진입점을 가리키고 있습니다.

clr!Unknown_QueryInterface:
clr!Unknown_AddRef:
clr!Unknown_Release:
clr!Dispatch_GetTypeInfoCount_Wrapper:
clr!Dispatch_GetTypeInfo_Wrapper:
clr!Dispatch_GetIDsOfNames_Wrapper:
clr!Dispatch_Invoke_Wrapper:

이는 IUnknown/IDispatch에서 정의한 함수의 순서와 정확히 일치합니다.

MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
IUnknown
{
public:
    BEGIN_INTERFACE
    virtual HRESULT STDMETHODCALLTYPE QueryInterface( 
        /* [in] */ REFIID riid,
        /* [annotation][iid_is][out] */ 
        _COM_Outptr_  void **ppvObject) = 0;
        
    virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
        
    virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
        
    END_INTERFACE
};

MIDL_INTERFACE("00020400-0000-0000-C000-000000000046")
IDispatch : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
        /* [out] */ __RPC__out UINT *pctinfo) = 0;
        
    virtual HRESULT STDMETHODCALLTYPE GetTypeInfo( 
        /* [in] */ UINT iTInfo,
        /* [in] */ LCID lcid,
        /* [out] */ __RPC__deref_out_opt ITypeInfo **ppTInfo) = 0;
        
    virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( 
        /* [in] */ __RPC__in REFIID riid,
        /* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR *rgszNames,
        /* [range][in] */ __RPC__in_range(0,16384) UINT cNames,
        /* [in] */ LCID lcid,
        /* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID *rgDispId) = 0;
        
    virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( 
        /* [annotation][in] */ 
        _In_  DISPID dispIdMember,
        /* [annotation][in] */ 
        _In_  REFIID riid,
        /* [annotation][in] */ 
        _In_  LCID lcid,
        /* [annotation][in] */ 
        _In_  WORD wFlags,
        /* [annotation][out][in] */ 
        _In_  DISPPARAMS *pDispParams,
        /* [annotation][out] */ 
        _Out_opt_  VARIANT *pVarResult,
        /* [annotation][out] */ 
        _Out_opt_  EXCEPINFO *pExcepInfo,
        /* [annotation][out] */ 
        _Out_opt_  UINT *puArgErr) = 0;
};




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]





[최초 등록일: ]
[최종 수정일: 2/28/2020 ]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer@outlook.com

비밀번호

댓글 쓴 사람
 




... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
12045정성태10/27/2019828오류 유형: 576. mstest.exe 실행 시 "Visual Studio Enterprise is required to execute the test." 오류 - 두 번째 이야기
12044정성태10/27/20191021오류 유형: 575. mstest.exe - System.Resources.MissingSatelliteAssemblyException: The satellite assembly named "Microsoft.VisualStudio.ProductKeyDialog.resources.dll, ..."
12043정성태10/27/20191140오류 유형: 574. Windows 10 설치 시 오류 - 0xC1900101 - 0x4001E
12042정성태10/26/20191081오류 유형: 573. OneDrive 하위에 위치한 Documents, Desktop 폴더에 대한 권한 변경 시 "Unable to display current owner"
12041정성태10/23/2019839오류 유형: 572. mstest.exe - The load test results database could not be opened.
12040정성태10/23/20191326오류 유형: 571. Unhandled Exception: System.Net.Mail.SmtpException: Transaction failed. The server response was: 5.2.0 STOREDRV.Submission.Exception:SendAsDeniedException.MapiExceptionSendAsDenied
12039정성태10/22/2019945스크립트: 16. cmd.exe의 for 문에서는 ERRORLEVEL이 설정되지 않는 문제
12038정성태10/17/2019774오류 유형: 570. SQL Server 2019 RC1 - SQL Client Connectivity SDK 설치 오류
12037정성태10/15/20191326.NET Framework: 867. C# - Encoding.Default 값을 바꿀 수 있을까요?파일 다운로드1
12036정성태10/21/20192314.NET Framework: 866. C# - 고성능이 필요한 환경에서 GC가 발생하지 않는 네이티브 힙 사용파일 다운로드1
12035정성태10/13/20191181개발 환경 구성: 461. C# 8.0의 #nulable 관련 특성을 .NET Framework 프로젝트에서 사용하는 방법파일 다운로드1
12034정성태1/31/20201434개발 환경 구성: 460. .NET Core 환경에서 (프로젝트가 아닌) C# 코드 파일을 입력으로 컴파일하는 방법 [1]
12033정성태10/19/20202317개발 환경 구성: 459. .NET Framework 프로젝트에서 C# 8.0/9.0 컴파일러를 사용하는 방법
12032정성태11/25/20191414.NET Framework: 865. .NET Core 2.2/3.0 웹 프로젝트를 IIS에서 호스팅(Inproc, out-of-proc)하는 방법 - AspNetCoreModuleV2 소개
12031정성태10/7/2019809오류 유형: 569. Azure Site Extension 업그레이드 시 "System.IO.IOException: There is not enough space on the disk" 예외 발생
12030정성태11/12/20192808.NET Framework: 864. .NET Conf 2019 Korea - "닷넷 17년의 변화 정리 및 닷넷 코어 3.0" 발표 자료 [1]파일 다운로드1
12029정성태9/27/20191004제니퍼 .NET: 29. Jennifersoft provides a trial promotion on its APM solution such as JENNIFER, PHP, and .NET in 2019 and shares the examples of their application.
12028정성태9/26/20191162.NET Framework: 863. C# - Thread.Suspend 호출 시 응용 프로그램 hang 현상을 해결하기 위한 시도파일 다운로드1
12027정성태9/26/2019718오류 유형: 568. Consider app.config remapping of assembly "..." from Version "..." [...] to Version "..." [...] to solve conflict and get rid of warning.
12026정성태9/26/20191122.NET Framework: 862. C# - Active Directory의 LDAP 경로 및 정보 조회
12025정성태9/25/20191142제니퍼 .NET: 28. APM 솔루션 제니퍼, PHP, .NET 무료 사용 프로모션 2019 및 적용 사례 (8)
12024정성태9/20/20191310.NET Framework: 861. HttpClient와 HttpClientHandler의 관계
12023정성태9/19/20191335.NET Framework: 860. ServicePointManager.DefaultConnectionLimit와 HttpClient의 관계파일 다운로드1
12022정성태9/12/20192660개발 환경 구성: 458. C# 8.0 (Preview) 신규 문법을 위한 개발 환경 구성 [3]
12021정성태11/12/20207814도서: 시작하세요! C# 8.0 프로그래밍 [3]
12020정성태9/11/20191427VC++: 134. SYSTEMTIME 값 기준으로 특정 시간이 지났는지를 판단하는 함수
... [16]  17  18  19  20  21  22  23  24  25  26  27  28  29  30  ...