성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Roll A Lisp In C - Reading ; https...
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# DLL에서 Win32 C/C++처럼 dllexport 함수를 제공하는 방법 - 네 번째 이야기(IL 코드로 직접 구현)</h1> <p> 아래의 글을 쓰다 보니,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# DLL에서 Win32 C/C++처럼 dllexport 함수를 제공하는 방법 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/11052'>https://www.sysnet.pe.kr/2/0/11052</a> C# DLL에서 Win32 C/C++처럼 dllexport 함수를 제공하는 방법 - 두 번째 이야기 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/11884'>https://www.sysnet.pe.kr/2/0/11884</a> C# DLL에서 Win32 C/C++처럼 dllexport 함수를 제공하는 방법 - 세 번째 이야기 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/12118'>http://www.sysnet.pe.kr/2/0/12118</a> </pre> <br /> 원론적인 이야기가 궁금해졌습니다. 찾아보면, IL 코드 수준에서 export하는 방법을 다음의 글에서 소개하고 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Unmanaged code can wrap managed methods ; <a target='tab' href='https://www.codeproject.com/Articles/8124/Unmanaged-code-can-wrap-managed-methods'>https://www.codeproject.com/Articles/8124/Unmanaged-code-can-wrap-managed-methods</a> </pre> <br /> 그리고 저 글을 쓴 사람은 Inside IL Assembler 책에서 단서를 얻었다고 하는데 실제로 그 책에 실린 "Figure 18-3. Indirect referencing of v-table entries from the EAT"가 그 구조를 담고 있습니다.<br /> <br /> [출처: <a target='tab' href='https://books.google.co.kr/books?id=Xv_0AwAAQBAJ&pg=PA353'>https://books.google.co.kr/books?id=Xv_0AwAAQBAJ&pg=PA353</a>]<br /> <img alt='il_export_1.png' src='/SysWebRes/bbs/il_export_1.png' /><br /> <br /> (0x25ff는 절대 주소로의 JMP 구문인데 그것이 v-table의 MethodDef 값을 참조한다는 것이 직관적이지는 않습니다. 그냥 전체적인 동작 의미로 유추해 해석하면 될 듯합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 일단, IL assembler 2.0 규격으로 export 함수를 구현하는 방법을 먼저 살펴보겠습니다. 예를 들기 위해 C#으로 다음과 같은 소스 코드를,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; public class Class1 { public static void Func1() // export할 함수 1 { Console.WriteLine("Func1"); return; } public static int Func2() // export할 함수 2 { return 5; } public static void Func3(int n) // export할 함수 3 { Console.WriteLine(n); } } </pre> <br /> 빌드해 DLL을 얻고, 그것을 다시 ildasm.exe를 통해 IL 코드로 번역합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ildasm ClassLibrary1.dll /out=ClassLibrary1.il </pre> <br /> 그럼 다음과 같은 출력 결과를 얻게 되는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // Metadata version: v4.0.30319 .assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .ver 4:0:0:0 } .assembly ClassLibrary1 { // ...[생략]... .hash algorithm 0x00008004 .ver 1:0:0:0 } .module ClassLibrary1.dll // MVID: {16FD8023-BE13-4D5D-8491-55801E2D5C90} .imagebase 0x10000000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI <span style='color: blue; font-weight: bold'>.corflags 0x00000001 // ILONLY</span> // Image base: 0x06B90000 // =============== CLASS MEMBERS DECLARATION =================== .class public abstract auto ansi sealed beforefieldinit Class1 extends [mscorlib]System.Object { .method public hidebysig static void Func1() cil managed { // Code size 15 (0xf) .maxstack 8 IL_0000: nop IL_0001: ldstr "Func1" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: br.s IL_000e IL_000e: ret } // end of method Class1::Func1 .method public hidebysig static int32 Func2() cil managed { // Code size 7 (0x7) .maxstack 1 .locals init ([0] int32 V_0) IL_0000: nop IL_0001: ldc.i4.5 IL_0002: stloc.0 IL_0003: br.s IL_0005 IL_0005: ldloc.0 IL_0006: ret } // end of method Class1::Func2 .method public hidebysig static void Func3(int32 n) cil managed { // Code size 9 (0x9) .maxstack 8 IL_0000: nop IL_0001: ldarg.0 IL_0002: call void [mscorlib]System.Console::WriteLine(int32) IL_0007: nop IL_0008: ret } // end of method Class1::Func3 } // end of class Class1 </pre> <br /> export할 메서드에 대해 단순히 다음과 같이 IL 언어로 표시만 해주면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .method public hidebysig static void Func1() cil managed { // Code size 15 (0xf) <span style='color: blue; font-weight: bold'>.export [1]</span> // 1 == ordinal number .maxstack 8 IL_0000: nop ...[생략]... IL_000e: ret } // end of method Class1::Func1 .method public hidebysig static int32 Func2() cil managed { // Code size 7 (0x7) <span style='color: blue; font-weight: bold'>.export [2]</span> // 2 == ordinal number .maxstack 1 .locals init ([0] int32 V_0) IL_0000: nop ...[생략]... IL_0006: ret } // end of method Class1::Func2 .method public hidebysig static void Func3(int32 n) cil managed { // Code size 9 (0x9) <span style='color: blue; font-weight: bold'>.export [3]</span> // 3 == ordinal number .maxstack 8 IL_0000: nop ...[생략]... IL_0008: ret } // end of method Class1::Func3 </pre> <br /> 그다음 IL 언어로만 구성되었다는 표시를 제거하는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .corflags 0x00000001 // ILONLY </pre> <br /> 32비트 assembly를 생성하는 경우에는 2로, 64비트 assembly를 생성하는 경우에는 0으로 지정합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // 32bit .corflags 0x00000002 // 64bit .corflags 0x00000000 </pre> <br /> 끝입니다. 이렇게만 바꾸고 ilasm.exe로 빌드하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // 32bit ilasm ClassLibrary1.il /RESOURCE=ClassLibrary1.res /DLL // 64 bit ilasm ClassLibrary1.il /RESOURCE=ClassLibrary1.res /DLL /X64 </pre> <br /> "Figure 18-3. Indirect referencing of v-table entries from the EAT"에서 보여준 V-Table, VT Fixup Table은 모두 자동으로 생성되고 ".export [<ordinal>] as <export_name>"으로 명시한 부분이 PE 포맷의 <a target='tab' href='http://www.sysnet.pe.kr/2/0/12093'>IMAGE_EXPORT_DIRECTORY</a>에 기록됩니다. 자, 그럼 마저 확인을 해봐야겠지요. ^^ ilasm.exe로 다시 빌드하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp> <span style='color: blue; font-weight: bold'>ilasm ClassLibrary1.il /RESOURCE=ClassLibrary1.res /DLL /X64</span> 64 bit target must be specified for machine type /ITANIUM or /X64. Target set to 64 bit. Microsoft (R) .NET Framework IL Assembler. Version 4.8.3752.0 Copyright (c) Microsoft Corporation. All rights reserved. Assembling 'ClassLibrary1.il' to DLL --> 'ClassLibrary1.dll' Source file is ANSI Assembled method Class1::Func1 Assembled method Class1::Func2 Assembled method Class1::Func3 Creating PE file Emitting classes: Class 1: Class1 Emitting fields and methods: Global Class 1 Methods: 3; Emitting events and properties: Global Class 1 Writing PE file Operation completed successfully </pre> <br /> dumpbin.exe 도구를 이용해 ilasm.exe가 출력한 DLL을 조사해 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp> <span style='color: blue; font-weight: bold'>dumpbin /EXPORTS ClassLibrary1.dll</span> Microsoft (R) COFF/PE Dumper Version 14.24.28314.0 Copyright (C) Microsoft Corporation. All rights reserved. Dump of file ClassLibrary1.dll File Type: DLL Section contains the following exports for ClassLibrary1.dll 00000000 characteristics 5E23CEF5 time date stamp Sun Jan 19 12:37:25 2020 0.00 version 1 ordinal base 3 number of functions 3 number of names ordinal hint RVA name 1 0 00002622 <span style='color: blue; font-weight: bold'>Func1</span> 2 1 0000262E <span style='color: blue; font-weight: bold'>Func2</span> 3 2 0000263A <span style='color: blue; font-weight: bold'>Func3</span> Summary 2000 .reloc 2000 .rsrc <span style='color: blue; font-weight: bold'>2000 .sdata</span> 2000 .text </pre> <br /> Func1, Func2, Func3이 export되었고 이와 함께 전에는 없던 (_MEM_WRITE 속성이 있는) ".sdata" 섹션이 생긴 것을 확인할 수 있습니다. (.export에 의해 생성되는 EAT와 자동으로 구성되는 V-Table이 .sdata 섹션에 위치하고, VT Fix up Table은 .text 섹션에 위치한다고 합니다.)<br /> <br /> export한 함수가 정상적으로 동작하는지, 또 다른 Console 응용 프로그램으로 DllImport를 이용해 호출까지 하는 것으로 확인을 완료할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.Runtime.InteropServices; class Program { <span style='color: blue; font-weight: bold'>[DllImport("ClassLibrary1.dll")] public static extern void Func1(); [DllImport("ClassLibrary1.dll")] public static extern int Func2(); [DllImport("ClassLibrary1.dll")] public static extern void Func3(int n);</span> static void Main(string[] args) { Func1(); Console.WriteLine(Func2()); Func3(3); } } /* 출력 결과 Func1 5 3 */ </pre> <br /> <hr style='width: 50%' /><br /> <br /> 그러니까, 결국 특정 DLL에 정의된 메서드를 export하고 싶다면 1) 그 메서드를 식별할 수 있어야 하고 2) IL disasm의 결과에서 .corflags와 .export를 재정의/삽입한 다음 3) 다시 ilasm시키면 됩니다.<br /> <br /> 그래서 다음의 글에 실린 ExportDll.exe 도구는,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > How to Automate Exporting .NET Function to Unmanaged Programs ; <a target='tab' href='https://www.codeproject.com/Articles/16310/How-to-Automate-Exporting-NET-Function-to-Unmanage'>https://www.codeproject.com/Articles/16310/How-to-Automate-Exporting-NET-Function-to-Unmanage</a> </pre> <br /> ildasm.exe로 얻은 il 코드에서 ExportDllAttribute가 설정된 메서드를 "텍스트"로써 찾은 다음 "// Code"라는 주석을 기준으로 ".export ..." 항목을 심어 다시 ilasm.exe하는 단순한 역할을 합니다. 즉, 복잡한 것은 ildasm.exe/ilasm.exe가 모두 대신하고 있는 것입니다.<br /> <br /> 정리하면, ExportDLL.exe의 IL 코드 변환 부분만 아주 쉽게 재작성해 보면 다음과 같은 정도로 나타낼 수 있는 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System.IO; using System.Text; namespace MakeExport { class Program { static void Main(string[] args) { string filePath = args[0]; string targetPlatform = args[1]; int index = 1; StringBuilder sb = new StringBuilder(); foreach (string line in File.ReadAllLines(filePath)) { if (line.IndexOf("// Code size") == -1) { sb.AppendLine(line); } else if (line.IndexOf(".corflags") != -1) { if (targetPlatform == "x64") { sb.AppendLine(".corflags 0x00000000"); } else { sb.AppendLine(".corflags 0x00000002"); } } else { sb.AppendLine(line); sb.AppendLine($".export[{index}]"); index++; } } File.WriteAllText(filePath, sb.ToString()); } } } </pre> <br /> 그래서 이것을 적절하게 batch 스크립트와 함께 작성해 주면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > SET BUILDCONFIG=Debug SET DLLNAME=ClassLibrary1 SET TARGETPLATFORM=x64 <span style='color: blue; font-weight: bold'>ildasm %DLLNAME%.dll /out=%DLLNAME%.il</span> <span style='color: blue; font-weight: bold'>MakeExport.exe %DLLNAME%.il %TARGETPLATFORM%</span> if '%TARGETPLATFORM%' == 'x64' ( <span style='color: blue; font-weight: bold'>ilasm %DLLNAME%.il /RESOURCE=%DLLNAME%.res /DLL /X64</span> ) else ( <span style='color: blue; font-weight: bold'>ilasm %DLLNAME%.il /RESOURCE=%DLLNAME%.res /DLL</span> ) </pre> <br /> 나름의 ExportDll.exe 역할을 하게 됩니다. ^^<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1534&boardid=331301885'>첨부 파일은 위의 예제를 모아두었고</a>, 빌드한 다음 ClassLibrary1.csproj가 있는 폴더의 il_export.bat를 "Developer Command Prompt for VS 2019" 명령행에서 실행하면 됩니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> 기왕 알아본 김에 조금 더 내려가보겠습니다. IL assembler 2.0 규격으로 ".export"를 지정하면 V-Table, VT Fixup Table을 자동으로 구성해 준다고 했는데요. 당연히 수작업으로 구성할 수도 있습니다.<br /> <br /> VT Fixup Table은 ".vtfixup" 코드로 구성되는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .vtfixup [<num_slots>] <flags> at <data_label> 예) .vtfixup [1] int32 fromunmanaged at VT_01 .data VT_01 = int32(0x0600001A) </pre> <br /> ".vtfixup"은 다중으로 정의할 수 있고 개별적으로 "테이블"이 구성됩니다. 해당 테이블에 담을 항목 수는 "[num_slots]"에 지정된 숫자가 결정하며 그 테이블에 들어갈 entry의 규격은 "data_label"로 연결된 항목으로 결정됩니다. 즉, 위와 같은 경우에는 int32로 지정되었기 때문에 slot 1개를 가진 테이블 하나를 정의한 것입니다.<br /> <br /> 가령 메서드 3개를 export하고 싶다면 다음과 같은 식으로 정의할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // 32비트인 경우 .vtfixup [1] int32 fromunmanaged at VT_01 .data VT_01 = int32(0x0600001A) .vtfixup [1] int32 fromunmanaged at VT_02 .data VT_02 = int32(0x0600001B) .vtfixup [1] int32 fromunmanaged at VT_03 .data VT_03 = int32(0x0600001C) // 64비트인 경우 .vtfixup [1] int64 fromunmanaged at VT_01 .data VT_01 = int64(0x0600001A) .vtfixup [1] int64 fromunmanaged at VT_02 .data VT_02 = int64(0x0600001B) .vtfixup [1] int64 fromunmanaged at VT_03 .data VT_03 = int64(0x0600001C) </pre> <br /> 여기서 0x0600001A, 0x0600001B, 0x0600001C 값은 EAT와 연결될 메서드의 MethodToken 값이기 때문에 이것을 일일이 알아내서 연결하는 것은 불편하므로 ilasm.exe로 하여금 자동으로 연결하도록 0을 지정하는 것이 좋습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .vtfixup [1] int32 fromunmanaged at VT_01 .data VT_01 = int32(0) .vtfixup [1] int32 fromunmanaged at VT_02 .data VT_02 = int32(0) .vtfixup [1] int32 fromunmanaged at VT_03 .data VT_03 = int32(0) </pre> <br /> 그리고 어차피 저렇게 생성된 3개의 테이블은 내부 slot의 규격이 같기 때문에 편의상 다음과 같이 1개로 정의하는 것도 가능합니다. <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // 32비트인 경우 .vtfixup [3] int32 fromunmanaged at VT_01 .data VT_01 = int32(0)[3] // 64비트인 경우 .vtfixup [3] int64 fromunmanaged at VT_01 .data VT_01 = int64(0)[3] </pre> <br /> 마지막으로, 이렇게 정의된 VT Fixup Table과 EAT와 연결해야 하는데 그 역할을 각 메서드의 ".vtentry"로 할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .vtentry <entry_number> : <slot_number> </pre> <br /> 첫 번째 entry_number는 VT Fixup Table을 지정하고, 두 번째 slot_number는 해당 Table 내의 slot 인덱스를 지정합니다. 따라서 3개의 vtfixup으로 정의한 경우라면 이렇게 .vtentry를 사용하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .method public hidebysig static void Func1() cil managed { .vtentry 1:1 .export [1] ...[생략]... } // end of method Class1::Func1 .method public hidebysig static int32 Func2() cil managed { .vtentry 2:1 .export [2] ...[생략]... } // end of method Class1::Func2 .method public hidebysig static void Func3(int32 n) cil managed { .vtentry 3:1 .export [3] ...[생략]... } // end of method Class1::Func3 </pre> <br /> 3개의 slot을 가진 한 개의 vtfixup으로 정의한 경우라면 다음과 같이 지정하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .method public hidebysig static void Func1() cil managed { .vtentry 1:1 .export [1] ...[생략]... } // end of method Class1::Func1 .method public hidebysig static int32 Func2() cil managed { .vtentry 1:2 .export [2] ...[생략]... } // end of method Class1::Func2 .method public hidebysig static void Func3(int32 n) cil managed { .vtentry 1:3 .export [3] ...[생략]... } // end of method Class1::Func3 </pre> <br /> 다행히 여기까지가 IL 수준에서 들어갈 수 있는 최대 깊이입니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> "<a target='tab' href='https://www.codeproject.com/Articles/8124/Unmanaged-code-can-wrap-managed-methods'>Unmanaged code can wrap managed methods</a>" 글에 실린 IL 코드를 ilasm.exe로 실행한다면 다음과 같은 오류가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\temp> <span style='color: blue; font-weight: bold'>ilasm test.il</span> Microsoft (R) .NET Framework IL Assembler. Version 4.8.3752.0 Copyright (c) Microsoft Corporation. All rights reserved. Assembling 'test.il' to EXE --> 'test.exe' Source file is ANSI test.il(43) : error : syntax error at token 'from' in: .vtfixup [1] int32 from unmanaged at VT_01 ***** FAILURE ***** </pre> <br /> (그 당시의 상황에서는 잘 되었을지도 모르지만) 43라인의 코드가,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .vtfixup [1] int32 <span style='color: blue; font-weight: bold'>from unmanaged</span> at VT_01 </pre> <br /> 이렇게 바뀌어야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .vtfixup [1] int32 <span style='color: blue; font-weight: bold'>fromunmanaged</span> at VT_01 </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1855
(왼쪽의 숫자를 입력해야 합니다.)