CryptoInfoGen Source Copy
이 파일은 프로젝트 소스 파일을 한곳에 모아둔 복사본입니다. bin/obj 산출물과 xlsx 바이너리는 제외했습니다.
CryptoInfoGen.csproj
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{3FA4E432-1BE5-48DE-997E-41A1D5DF12B1}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>CryptoInfoGen</RootNamespace>
<AssemblyName>CryptoInfoGen</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CryptoInfoGen
{
internal static class Program
{
/// <summary>
/// 해당 애플리케이션의 주 진입점입니다.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Form1.cs
using System;
using System.Collections.Generic;
using System.Data.Odbc;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
namespace CryptoInfoGen
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var samplePath = Path.Combine(Application.StartupPath, "..", "..", "통합 문서.xlsx");
samplePath = Path.GetFullPath(samplePath);
if (File.Exists(samplePath))
{
txtExcelPath.Text = samplePath;
}
}
private void btnBrowse_Click(object sender, EventArgs e)
{
if (openFileDialog.ShowDialog(this) == DialogResult.OK)
{
txtExcelPath.Text = openFileDialog.FileName;
}
}
private void btnGenerate_Click(object sender, EventArgs e)
{
try
{
labelStatus.Text = "생성 중...";
txtOutput.Clear();
var excelPath = txtExcelPath.Text.Trim();
var connectionString = txtConnectionString.Text.Trim();
if (string.IsNullOrWhiteSpace(excelPath) || !File.Exists(excelPath))
{
MessageBox.Show(this, "엑셀 파일 경로를 확인하세요.", "입력 오류", MessageBoxButtons.OK, MessageBoxIcon.Warning);
labelStatus.Text = "엑셀 파일 경로가 올바르지 않습니다.";
return;
}
if (string.IsNullOrWhiteSpace(connectionString))
{
MessageBox.Show(this, "ODBC 연결 문자열을 입력하세요.", "입력 오류", MessageBoxButtons.OK, MessageBoxIcon.Warning);
labelStatus.Text = "ODBC 연결 문자열이 비어 있습니다.";
return;
}
var tables = ExcelTableReader.Read(excelPath);
if (tables.Count == 0)
{
MessageBox.Show(this, "엑셀에서 테이블/컬럼 정보를 찾지 못했습니다.", "데이터 없음", MessageBoxButtons.OK, MessageBoxIcon.Information);
labelStatus.Text = "생성할 데이터가 없습니다.";
return;
}
var primaryKeys = OraclePrimaryKeyReader.Read(connectionString, tables.Select(t => t.Name));
txtOutput.Text = SourceCodeBuilder.Build(tables, primaryKeys);
labelStatus.Text = string.Format("{0}개 테이블의 소스 코드를 생성했습니다.", tables.Count);
}
catch (Exception ex)
{
labelStatus.Text = "생성 실패: " + ex.Message;
MessageBox.Show(this, ex.ToString(), "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private sealed class TableInfo
{
public TableInfo(string name)
{
Name = name;
Columns = new List<string>();
HandlerTypes = new List<string>();
}
public string Name { get; private set; }
public List<string> Columns { get; private set; }
public List<string> HandlerTypes { get; private set; }
}
private static class ExcelTableReader
{
private static readonly XNamespace SpreadsheetNamespace = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
private static readonly XNamespace RelationshipsNamespace = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
private static readonly XNamespace PackageRelationshipsNamespace = "http://schemas.openxmlformats.org/package/2006/relationships";
public static List<TableInfo> Read(string excelPath)
{
using (var archive = ZipFile.OpenRead(excelPath))
{
var sharedStrings = ReadSharedStrings(archive);
var worksheetEntry = GetFirstWorksheetEntry(archive);
if (worksheetEntry == null)
{
throw new InvalidOperationException("엑셀 파일에서 첫 번째 워크시트를 찾지 못했습니다.");
}
var rows = ReadRows(worksheetEntry, sharedStrings);
return ConvertRows(rows);
}
}
private static List<string> ReadSharedStrings(ZipArchive archive)
{
var entry = archive.GetEntry("xl/sharedStrings.xml");
if (entry == null)
{
return new List<string>();
}
var document = LoadXml(entry);
return document.Descendants(SpreadsheetNamespace + "si")
.Select(si => string.Concat(si.Descendants(SpreadsheetNamespace + "t").Select(t => t.Value)))
.ToList();
}
private static ZipArchiveEntry GetFirstWorksheetEntry(ZipArchive archive)
{
var workbookEntry = archive.GetEntry("xl/workbook.xml");
var relsEntry = archive.GetEntry("xl/_rels/workbook.xml.rels");
if (workbookEntry == null || relsEntry == null)
{
return archive.GetEntry("xl/worksheets/sheet1.xml");
}
var workbook = LoadXml(workbookEntry);
var rels = LoadXml(relsEntry);
var firstSheet = workbook.Descendants(SpreadsheetNamespace + "sheet").FirstOrDefault();
if (firstSheet == null)
{
return archive.GetEntry("xl/worksheets/sheet1.xml");
}
var relId = (string)firstSheet.Attribute(RelationshipsNamespace + "id");
var relationship = rels.Descendants(PackageRelationshipsNamespace + "Relationship")
.FirstOrDefault(r => string.Equals((string)r.Attribute("Id"), relId, StringComparison.Ordinal));
var target = relationship == null ? "worksheets/sheet1.xml" : (string)relationship.Attribute("Target");
var entryName = "xl/" + target.Replace('\\', '/').TrimStart('/');
return archive.GetEntry(entryName);
}
private static List<List<string>> ReadRows(ZipArchiveEntry worksheetEntry, List<string> sharedStrings)
{
var document = LoadXml(worksheetEntry);
var result = new List<List<string>>();
foreach (var row in document.Descendants(SpreadsheetNamespace + "row"))
{
var values = new SortedDictionary<int, string>();
foreach (var cell in row.Elements(SpreadsheetNamespace + "c"))
{
var reference = (string)cell.Attribute("r");
var columnIndex = GetColumnIndex(reference);
values[columnIndex] = ReadCellValue(cell, sharedStrings);
}
if (values.Count == 0)
{
continue;
}
var maxIndex = values.Keys.Max();
var rowValues = new List<string>();
for (var i = 0; i <= maxIndex; i++)
{
string value;
rowValues.Add(values.TryGetValue(i, out value) ? value.Trim() : string.Empty);
}
result.Add(rowValues);
}
return result;
}
private static string ReadCellValue(XElement cell, List<string> sharedStrings)
{
var type = (string)cell.Attribute("t");
if (string.Equals(type, "inlineStr", StringComparison.OrdinalIgnoreCase))
{
return string.Concat(cell.Descendants(SpreadsheetNamespace + "t").Select(t => t.Value));
}
var value = (string)cell.Element(SpreadsheetNamespace + "v") ?? string.Empty;
if (string.Equals(type, "s", StringComparison.OrdinalIgnoreCase))
{
int sharedIndex;
if (int.TryParse(value, out sharedIndex) && sharedIndex >= 0 && sharedIndex < sharedStrings.Count)
{
return sharedStrings[sharedIndex];
}
}
return value;
}
private static List<TableInfo> ConvertRows(List<List<string>> rows)
{
var headerIndex = FindHeaderIndex(rows);
var tableColumnIndex = headerIndex >= 0 ? FindColumnIndex(rows[headerIndex], "테이블", "table") : 0;
var columnColumnIndex = headerIndex >= 0 ? FindColumnIndex(rows[headerIndex], "컬럼", "column", "col") : 1;
var handlerColumnIndex = headerIndex >= 0 ? FindColumnIndex(rows[headerIndex], "핸들러", "handler", "handtype", "type") : 2;
if (tableColumnIndex < 0)
{
tableColumnIndex = 0;
}
if (columnColumnIndex < 0)
{
columnColumnIndex = 1;
}
if (handlerColumnIndex < 0)
{
handlerColumnIndex = 2;
}
var tableMap = new Dictionary<string, TableInfo>(StringComparer.OrdinalIgnoreCase);
var tableOrder = new List<TableInfo>();
foreach (var row in rows.Skip(headerIndex >= 0 ? headerIndex + 1 : 0))
{
var tableName = GetValue(row, tableColumnIndex);
var columnName = GetValue(row, columnColumnIndex);
var handlerType = GetValue(row, handlerColumnIndex);
if (string.IsNullOrWhiteSpace(tableName) || string.IsNullOrWhiteSpace(columnName))
{
continue;
}
TableInfo table;
if (!tableMap.TryGetValue(tableName, out table))
{
table = new TableInfo(tableName);
tableMap.Add(tableName, table);
tableOrder.Add(table);
}
table.Columns.Add(columnName);
table.HandlerTypes.Add(handlerType);
}
return tableOrder;
}
private static int FindHeaderIndex(List<List<string>> rows)
{
for (var i = 0; i < rows.Count; i++)
{
var joined = string.Join("|", rows[i]).ToLowerInvariant();
if ((joined.Contains("테이블") || joined.Contains("table")) &&
(joined.Contains("컬럼") || joined.Contains("column") || joined.Contains("col")))
{
return i;
}
}
return -1;
}
private static int FindColumnIndex(List<string> row, params string[] keys)
{
for (var i = 0; i < row.Count; i++)
{
var value = row[i].Trim().ToLowerInvariant();
if (keys.Any(key => value.Contains(key.ToLowerInvariant())))
{
return i;
}
}
return -1;
}
private static string GetValue(List<string> row, int index)
{
return index >= 0 && index < row.Count ? row[index].Trim() : string.Empty;
}
private static int GetColumnIndex(string cellReference)
{
if (string.IsNullOrEmpty(cellReference))
{
return 0;
}
var column = 0;
foreach (var ch in cellReference)
{
if (!char.IsLetter(ch))
{
break;
}
column = column * 26 + (char.ToUpperInvariant(ch) - 'A' + 1);
}
return Math.Max(0, column - 1);
}
private static XDocument LoadXml(ZipArchiveEntry entry)
{
using (var stream = entry.Open())
{
return XDocument.Load(stream);
}
}
}
private static class OraclePrimaryKeyReader
{
public static Dictionary<string, List<string>> Read(string connectionString, IEnumerable<string> tableNames)
{
var normalizedNames = tableNames
.Where(name => !string.IsNullOrWhiteSpace(name))
.Select(name => name.Trim())
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
var result = normalizedNames.ToDictionary(name => name, name => new List<string>(), StringComparer.OrdinalIgnoreCase);
if (normalizedNames.Count == 0)
{
return result;
}
using (var connection = new OdbcConnection(connectionString))
{
connection.Open();
foreach (var batch in Split(normalizedNames, 900))
{
var placeholders = string.Join(",", batch.Select(_ => "?"));
var sql = @"
SELECT acc.table_name, acc.column_name
FROM all_constraints ac
JOIN all_cons_columns acc
ON ac.owner = acc.owner
AND ac.constraint_name = acc.constraint_name
AND ac.table_name = acc.table_name
WHERE ac.constraint_type = 'P'
AND ac.owner = SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA')
AND UPPER(acc.table_name) IN (" + placeholders + @")
ORDER BY acc.table_name, acc.position";
using (var command = new OdbcCommand(sql, connection))
{
foreach (var tableName in batch)
{
command.Parameters.Add("?", OdbcType.VarChar).Value = tableName.ToUpperInvariant();
}
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
var tableName = reader.GetString(0);
var columnName = reader.GetString(1);
List<string> keys;
if (result.TryGetValue(tableName, out keys) && !keys.Contains(columnName, StringComparer.OrdinalIgnoreCase))
{
keys.Add(columnName);
}
}
}
}
}
}
return result;
}
private static IEnumerable<List<string>> Split(List<string> values, int size)
{
for (var i = 0; i < values.Count; i += size)
{
yield return values.Skip(i).Take(size).ToList();
}
}
}
private static class SourceCodeBuilder
{
public static string Build(List<TableInfo> tables, Dictionary<string, List<string>> primaryKeys)
{
var builder = new StringBuilder();
builder.AppendLine("string[] arr = { " + JoinQuoted(tables.Select(t => t.Name)) + " };");
builder.AppendLine();
builder.AppendLine("String[] cols = { " + JoinQuoted(tables.Select(t => string.Join(",", t.Columns))) + " };");
builder.AppendLine();
builder.AppendLine("String[] handtype = { " + JoinQuoted(tables.Select(t => string.Join(",", t.HandlerTypes))) + " };");
builder.AppendLine();
builder.AppendLine("String[] pks = { " + JoinQuoted(tables.Select(t => GetPrimaryKeyText(primaryKeys, t.Name))) + " };");
return builder.ToString();
}
private static string GetPrimaryKeyText(Dictionary<string, List<string>> primaryKeys, string tableName)
{
List<string> keys;
return primaryKeys.TryGetValue(tableName, out keys) && keys.Count > 0
? string.Join(",", keys)
: "rowid";
}
private static string JoinQuoted(IEnumerable<string> values)
{
return string.Join(", ", values.Select(value => "\"" + Escape(value) + "\""));
}
private static string Escape(string value)
{
return (value ?? string.Empty).Replace("\\", "\\\\").Replace("\"", "\\\"");
}
}
}
}
Form1.Designer.cs
namespace CryptoInfoGen
{
partial class Form1
{
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.Label labelExcelPath;
private System.Windows.Forms.TextBox txtExcelPath;
private System.Windows.Forms.Button btnBrowse;
private System.Windows.Forms.Label labelConnectionString;
private System.Windows.Forms.TextBox txtConnectionString;
private System.Windows.Forms.Button btnGenerate;
private System.Windows.Forms.TextBox txtOutput;
private System.Windows.Forms.Label labelStatus;
private System.Windows.Forms.OpenFileDialog openFileDialog;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.labelExcelPath = new System.Windows.Forms.Label();
this.txtExcelPath = new System.Windows.Forms.TextBox();
this.btnBrowse = new System.Windows.Forms.Button();
this.labelConnectionString = new System.Windows.Forms.Label();
this.txtConnectionString = new System.Windows.Forms.TextBox();
this.btnGenerate = new System.Windows.Forms.Button();
this.txtOutput = new System.Windows.Forms.TextBox();
this.labelStatus = new System.Windows.Forms.Label();
this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
this.SuspendLayout();
//
// labelExcelPath
//
this.labelExcelPath.AutoSize = true;
this.labelExcelPath.Location = new System.Drawing.Point(16, 18);
this.labelExcelPath.Name = "labelExcelPath";
this.labelExcelPath.Size = new System.Drawing.Size(81, 12);
this.labelExcelPath.TabIndex = 0;
this.labelExcelPath.Text = "엑셀 파일 경로";
//
// txtExcelPath
//
this.txtExcelPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.txtExcelPath.Location = new System.Drawing.Point(16, 38);
this.txtExcelPath.Name = "txtExcelPath";
this.txtExcelPath.Size = new System.Drawing.Size(653, 21);
this.txtExcelPath.TabIndex = 1;
//
// btnBrowse
//
this.btnBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnBrowse.Location = new System.Drawing.Point(675, 36);
this.btnBrowse.Name = "btnBrowse";
this.btnBrowse.Size = new System.Drawing.Size(83, 25);
this.btnBrowse.TabIndex = 2;
this.btnBrowse.Text = "찾기";
this.btnBrowse.UseVisualStyleBackColor = true;
this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
//
// labelConnectionString
//
this.labelConnectionString.AutoSize = true;
this.labelConnectionString.Location = new System.Drawing.Point(16, 76);
this.labelConnectionString.Name = "labelConnectionString";
this.labelConnectionString.Size = new System.Drawing.Size(100, 12);
this.labelConnectionString.TabIndex = 3;
this.labelConnectionString.Text = "ODBC 연결 문자열";
//
// txtConnectionString
//
this.txtConnectionString.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.txtConnectionString.Location = new System.Drawing.Point(16, 96);
this.txtConnectionString.Name = "txtConnectionString";
this.txtConnectionString.Size = new System.Drawing.Size(653, 21);
this.txtConnectionString.TabIndex = 4;
//
// btnGenerate
//
this.btnGenerate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnGenerate.Location = new System.Drawing.Point(675, 94);
this.btnGenerate.Name = "btnGenerate";
this.btnGenerate.Size = new System.Drawing.Size(83, 25);
this.btnGenerate.TabIndex = 5;
this.btnGenerate.Text = "생성";
this.btnGenerate.UseVisualStyleBackColor = true;
this.btnGenerate.Click += new System.EventHandler(this.btnGenerate_Click);
//
// txtOutput
//
this.txtOutput.AcceptsReturn = true;
this.txtOutput.AcceptsTab = true;
this.txtOutput.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.txtOutput.Font = new System.Drawing.Font("Consolas", 10F);
this.txtOutput.Location = new System.Drawing.Point(16, 138);
this.txtOutput.Multiline = true;
this.txtOutput.Name = "txtOutput";
this.txtOutput.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.txtOutput.Size = new System.Drawing.Size(742, 354);
this.txtOutput.TabIndex = 6;
this.txtOutput.WordWrap = false;
//
// labelStatus
//
this.labelStatus.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.labelStatus.AutoEllipsis = true;
this.labelStatus.Location = new System.Drawing.Point(16, 503);
this.labelStatus.Name = "labelStatus";
this.labelStatus.Size = new System.Drawing.Size(742, 20);
this.labelStatus.TabIndex = 7;
this.labelStatus.Text = "엑셀 파일과 ODBC 연결 문자열을 입력한 뒤 생성하세요.";
//
// openFileDialog
//
this.openFileDialog.Filter = "Excel Workbook (*.xlsx)|*.xlsx|All files (*.*)|*.*";
this.openFileDialog.Title = "엑셀 파일 선택";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(774, 535);
this.Controls.Add(this.labelStatus);
this.Controls.Add(this.txtOutput);
this.Controls.Add(this.btnGenerate);
this.Controls.Add(this.txtConnectionString);
this.Controls.Add(this.labelConnectionString);
this.Controls.Add(this.btnBrowse);
this.Controls.Add(this.txtExcelPath);
this.Controls.Add(this.labelExcelPath);
this.MinimumSize = new System.Drawing.Size(640, 420);
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "CryptoInfoGen";
this.ResumeLayout(false);
this.PerformLayout();
}
}
}
Form1.resx
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
Properties\AssemblyInfo.cs
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("CryptoInfoGen")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CryptoInfoGen")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
[assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("3fa4e432-1be5-48de-997e-41a1d5df12b1")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//
// 주 버전
// 부 버전
// 빌드 번호
// 수정 버전
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
Properties\Resources.resx
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
Properties\Resources.Designer.cs
//------------------------------------------------------------------------------
// <auto-generated>
// 이 코드는 도구를 사용하여 생성되었습니다.
// 런타임 버전:4.0.30319.42000
//
// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
// 이러한 변경 내용이 손실됩니다.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CryptoInfoGen.Properties
{
/// <summary>
/// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
/// </summary>
// 이 클래스는 ResGen 또는 Visual Studio와 같은 도구를 통해 StronglyTypedResourceBuilder
// 클래스에서 자동으로 생성되었습니다.
// 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여
// ResGen을 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CryptoInfoGen.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대해 현재 스레드의 CurrentUICulture 속성을
/// 재정의합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}
Properties\Settings.settings
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
Properties\Settings.Designer.cs
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CryptoInfoGen.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}