블로그 이미지
보미아빠

카테고리

보미아빠, 석이 (528)
밥벌이 (16)
싸이클 (1)
일상 (1)
Total
Today
Yesterday

달력

« » 2025.9
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

공지사항

최근에 올라온 글

'보미아빠, 석이'에 해당되는 글 528건

  1. 2023.01.04 비동기 프로그램
  2. 2022.06.02 mssql transaction 처리
  3. 2022.05.24 multiThread test
  4. 2022.01.27 multisubnet connection test
  5. 2021.02.02 난독화
  6. 2019.11.15 개발인증서 생성과 자동 설치 및 포트 바인딩
  7. 2019.11.04 secureString
  8. 2019.10.31 Memento for restore state
  9. 2019.10.14 대역폭 제어 다운로드 2
  10. 2019.08.08 sql base64unicode convert function
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TaskTest2
{
    // Parallel execution can be performed as much as the specified number.
    // Job can be canceled.
    // You can set the task timeout.
    // When a task exception occurs, all workers can be stopped.

    internal class Program
    {
        static readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

        public static void Main(string[] args)
        {

            // Simulation of job cancellation time (external factor)
            DateTime endTime = DateTime.Now.Add(new TimeSpan(0, 0, 1000));

            Manager manager = new Manager(cancellationTokenSource);
            var task = manager.Run(maxDegreeOfParallelism: 10, workerCnt: 10, dummyWorkerIterationCnt: 10, errorPosition: 1);
            try
            {
                // Work cancellation The internal work must be completed within this time.
                task = AsyncExtensions.TimeoutAfter(task, TimeSpan.FromSeconds(100), cancellationTokenSource);
                while (!task.Wait(50))
                {
                    Console.Write(".");
                    if (DateTime.Now > endTime)
                        manager.Stop();
                }
            }
            catch (AggregateException aex)
            {
                foreach (var ex in aex.InnerExceptions)
                {
                    Console.WriteLine($@"main inner exception {ex.Message}");
                }
            }
            catch (TimeoutException ex)
            {
                Console.WriteLine($@"main timeout {ex.Message}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($@"main exception ex {ex.Message}");
            }
            Console.WriteLine("main program end");
        }
    }

    internal class Manager
    {
        CancellationTokenSource cancellationTokenSource;

        public Manager(CancellationTokenSource cancellationTokenSource)
        {
            this.cancellationTokenSource = cancellationTokenSource;
        }

        public void Stop()
        {
            cancellationTokenSource.Cancel();
            Console.WriteLine("cancel requested");
        }

        public async Task Run(int maxDegreeOfParallelism, int workerCnt, int dummyWorkerIterationCnt, int? errorPosition)
        {

            CancellationToken token = cancellationTokenSource.Token;
            List<Func<Task>> actionList = new List<Func<Task>>();

            for (int i = 0; i < workerCnt; i++)
            {
                int j = i;
                actionList.Add(() => new DummyWorker(token).DoWork(iteration: dummyWorkerIterationCnt, errorPosition: errorPosition));
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine($@"run token cancel requested");
                    break;
                }
            }



            try
            {
                await AsyncExtensions.InvokeAsync(actionList, maxDegreeOfParallelism: maxDegreeOfParallelism, token);
            }
            catch (Exception ex)
            {
                Console.WriteLine($@"run method exception {ex.Message}");
            }
            Console.WriteLine("end");

        }
    }

    internal class DummyWorker
    {
        CancellationToken token;

        public DummyWorker(CancellationToken token)
        {
            this.token = token;
        }

        public Task DoWork(int iteration, int? errorPosition)
        {
            var task = Task.Run(async () =>
            {
                for (int i = 0; i < iteration; i++)
                {
                    if (token.IsCancellationRequested)
                    {
                        Console.WriteLine($@"{GetType()} cancel requested");
                        break;
                    }
                    if (i == errorPosition)
                        throw new Exception("simulation exception : fire!");

                    // working...
                    await Task.Delay(500);

                    Console.WriteLine($@"working...iteration {i}");
                }
            }, token);
            return task;
        }
    }

    public static class AsyncExtensions
    {
        public static async Task<T> TimeoutAfter<T>(this Task<T> task, TimeSpan timeout, CancellationTokenSource cancellationTokenSource = null)
        {
            if (task == await Task.WhenAny(task, Task.Delay(timeout)))
                return await task;
            else
            {
                if (cancellationTokenSource != null)
                    cancellationTokenSource.Cancel();

                throw new TimeoutException();
            }
        }
        public static async Task TimeoutAfter(this Task task, TimeSpan timeout, CancellationTokenSource cancellationTokenSource = null)
        {
            if (task == await Task.WhenAny(task, Task.Delay(timeout)))
                await task;
            else
            {
                if (cancellationTokenSource != null)
                    cancellationTokenSource.Cancel();

                throw new TimeoutException();
            }
        }
        public static async Task InvokeAsync(IEnumerable<Func<Task>> taskFactories, int maxDegreeOfParallelism, CancellationToken token)
        {
            if (taskFactories == null) throw new ArgumentNullException(nameof(taskFactories));
            if (maxDegreeOfParallelism <= 0) throw new ArgumentException(nameof(maxDegreeOfParallelism));

            // Defensive copy. Similar to what Task.WhenAll/WhenAny does.
            Func<Task>[] queue = taskFactories.ToArray();

            if (queue.Length == 0)
            {
                return;
            }

            List<Task> tasksInFlight = new List<Task>(maxDegreeOfParallelism);
            int index = 0;

            do
            {
                while (tasksInFlight.Count < maxDegreeOfParallelism && index < queue.Length)
                {
                    if (token.IsCancellationRequested)
                        return;

                    Func<Task> taskFactory = queue[index++];

                    tasksInFlight.Add(taskFactory());
                }

                if (token.IsCancellationRequested)
                    return;

                Task completedTask = await Task.WhenAny(tasksInFlight).ConfigureAwait(false);

                try
                {
                    await completedTask.ConfigureAwait(false); // Check result.
                }
                catch
                {
                    throw;
                }

                tasksInFlight.Remove(completedTask);
            }
            while (index < queue.Length || tasksInFlight.Count != 0);
        }
    }
}
Posted by 보미아빠
, |
if object_id ('tblx') is not null
drop table tblx, tbly, tblz
go
 
create table tblx (id int, c int)
go
 
create table tbly (id int, c int)
go
 
create table tblz (idx bigint identity(1,1),etime datetime, emessage nvarchar(max), )
go
 
create unique nonclustered index nc_tbly_01 on tbly (id)
go
 
if object_id ('usp_a') is null
exec ('create proc usp_a as select 1')
go
 
alter proc usp_a
(
@id int,
@c int
)
as
set implicit_transactions on ; -- 암시적 트랜잭션
begin try -- try catch 로 transaction 처리 할 부분 전체를 감싼다.
insert into tblx (id, c) values (@id, @c)
insert into tbly (id, c) values (@id, @c)
commit tran ;
end try
begin catch
if @@trancount > 0
begin
rollback tran;
set implicit_transactions off ;
-- 추가적인 로깅을 하던지
DECLARE @ErrorMessage NVARCHAR(max) = ERROR_MESSAGE()
insert into tblz (etime, emessage) values (getdate(), @ErrorMessage)
end
end catch
go
 
-- 아래
-- 테스트 시작
select @@trancount
select * from tblx
select * from tbly
select * from tblz
go
-- 오류없는 테스트
exec usp_a 1,1
exec usp_a 2,2
go
-- 데이터 확인
select * from tblx
select * from tbly
select * from tblz
go
-- 에러상황 테스트
-- tbly 는 unique index 가 있어서 중복값이 들어가지 못하는 상황이다.
-- rollback 했을때 전체가 rollback 되어야 하므로 tblx 에도 1,1 이 중복해 들어가지 않기를 바란다.
exec usp_a 1,1
select * from tblz
go
-- 데이터 확인
-- tbly 에서 에러가 생겨 데이터가 들어가지 않았다.
select * from tblx
select * from tbly
select * from tblz
go
-- 따로는 데이터가 잘 들어간다.
insert into tblx (id, c) values (1,1)
go
-- 데이터 확인
select * from tblx
select * from tbly
select * from tblz
go
Posted by 보미아빠
, |

multiThread test

카테고리 없음 / 2022. 5. 24. 11:37

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace Helpers
{
    class ThreadedHelper<I,O>
    {
        public I input { get; set; }

        public ThreadedHelper(Func<I,O> doWork, Action<O> callback, Action<I, Exception> errorCallback)
        {
            this.doWork = doWork;
            this.callback = callback;
            this.errorCallback = errorCallback;
            t = new Thread(Process);
        }

        public void Start()
        {
            t.Start();
        }

        private void Process()
        {
            try
            {
                O retun = doWork(input);
                callback(retun);
            }
            catch (Exception ex)
            {
                errorCallback(input, ex);
                t.Abort();
            }
        }

        private Func<I,O> doWork;
        private Action<O> callback;
        private Action<I, Exception> errorCallback;

        private Thread t;


        // example
        // using System.Threading;
        // using Helpers;
        //class Program
        //{
        //    class Input
        //    {
        //        public int a { get; set; }
        //        public int b { get; set; }
        //    }

        //    class Output
        //    {
        //        public Input input { get; set; }
        //        public int result { get; set; }
        //    }

        //    static void Main(string[] args)
        //    {
        //        var p = new Program();

        //        new ThreadedHelper<Input, Output>(p.DoWork, p.Callback, p.ErrorCallback)
        //        {
        //            input = new Input { a = 4, b = 0 }
        //        }.Start();

        //        for (int i = 0; i < 30; i++)
        //        {
        //            Console.WriteLine("wait");
        //            Thread.Sleep(100);
        //        }

        //        Console.WriteLine("end");
        //        Console.ReadKey();
        //    }

        //    Output DoWork(Input input)
        //    {
        //        try
        //        {
        //            Thread.Sleep(2000);
        //            int s = input.a / input.b;
        //            return new Output { input = input, result = s };
        //        }
        //        catch (Exception ex)
        //        {
        //            throw ex;
        //        }
        //    }

        //    void Callback(Output output)
        //    {
        //        Console.WriteLine($@"output : {output.input.a},{output.input.b},{output.result}");
        //    }

        //    void ErrorCallback(Input i, Exception ex)
        //    {
        //        Console.WriteLine($@"output error : {i.a}, {i.b}, {ex.Message}, {ex.StackTrace}");
        //    }

        //}

    }
}

 

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace Helpers
{
    class ThreadedHelper<I,O>
    {
        public delegate O DoWork(I inValue);
        public delegate void CallBack(O outValue);
        public delegate void ErrorCallBack(I input, Exception message);
        public I input { get; set; }

        public ThreadedHelper(DoWork work, CallBack callback, ErrorCallBack errorCallback)
        {
            this.work = work;
            this.callback = callback;
            this.errorCallback = errorCallback; 
            t = new Thread(Process);
        }

        public void Start()
        {
            t.Start();
        }

        private void Process()
        {
            try
            {
                O retun = work(input);
                callback(retun);
            }
            catch (Exception ex)
            {
                errorCallback(input, ex);
                t.Abort();
            }
        }

        private DoWork work;
        private CallBack callback;
        private ErrorCallBack errorCallback;
        private Thread t;


        // example
        // using System.Threading;
        // using Helpers;
        //class Program
        //{
        //    class Input
        //    {
        //        public int a { get; set; }
        //        public int b { get; set; }
        //    }

        //    class Output
        //    {
        //        public Input input { get; set; }
        //        public int result { get; set; }
        //    }

        //    static void Main(string[] args)
        //    {
        //        var p = new Program();

        //        new ThreadedHelper<Input, Output>(p.DoWork, p.Callback, p.ErrorCallback)
        //        {
        //            input = new Input { a = 4, b = 0 }
        //        }.Start();

        //        for (int i = 0; i < 30; i++)
        //        {
        //            Console.WriteLine("wait");
        //            Thread.Sleep(100);
        //        }

        //        Console.WriteLine("end");
        //        Console.ReadKey();
        //    }

        //    Output DoWork(Input input)
        //    {
        //        try
        //        {
        //            Thread.Sleep(2000);
        //            int s = input.a / input.b;
        //            return new Output { input = input, result = s };
        //        }
        //        catch (Exception ex)
        //        {
        //            throw ex;
        //        }
        //    }

        //    void Callback(Output output)
        //    {
        //        Console.WriteLine($@"output : {output.input.a},{output.input.b},{output.result}");
        //    }

        //    void ErrorCallback(Input i, Exception ex)
        //    {
        //        Console.WriteLine($@"output error : {i.a}, {i.b}, {ex.Message}, {ex.StackTrace}");
        //    }

        //}

    }
}

Posted by 보미아빠
, |

타이머로 테스트 

ExTimer.zip
0.04MB

Posted by 보미아빠
, |

난독화

카테고리 없음 / 2021. 2. 2. 21:46

https://github.com/yck1509/ConfuserEx/releases 무료 난독화 
JetBrain DotPeeker 로 잘 안보임 

Posted by 보미아빠
, |

* 모두삭제
del hostname.*

* private key 와 인증서 및 인증서 암호를 입력한다. 
makecert -r -len 2048 -pe -n "CN=HOSTNAME" -eku 1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.3,1.3.6.1.5.5.7.3.4 -sky exchange -sv HOSTNAME.pvk HOSTNAME.cer -b 01/01/2005 -e 01/01/2035

* 암호입력
1234

* 포터블 파일로 변경한다. 
pvk2pfx -pvk HOSTNAME.pvk -spc HOSTNAME.cer -pfx HOSTNAME.pfx -pi 1234 -po 1234 -f

* pfx my, localhost 에 등록
* cer Root, localhost 에 등록 
certlm.mmc 에서 Personal + Trusted Root Certi 저장소에 HOSTNAME pfx 와 cert 파일이 있는지 확인한다. 
* 자동으로 등록하는 클래스 Certification.cs 확인 

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using CsLib; 

namespace WcfHttpsServer
{
    class Certification
    {

        public bool Bind(string path, string pfx, string pfxpassword, string cert, string port)
        {
            try
            {
                string pfxFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path, pfx);
                string certFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path, cert);

                DeleteCertification(pfxFileName
                    , StoreName.My
                    , StoreLocation.LocalMachine
                    , pfxpassword
                    , X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

                DeleteCertification(certFileName
                    , StoreName.Root
                    , StoreLocation.LocalMachine);

                InstallCertification(pfxFileName
                    , StoreName.My
                    , StoreLocation.LocalMachine
                    , pfxpassword
                    , X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);

                InstallCertification(certFileName
                    , StoreName.Root
                    , StoreLocation.LocalMachine);

                CertificationNetBind(certFileName, port);
            }
            catch (Exception)
            {
                throw;
            }
            return true;
        }

        private void InstallCertification(string certFileName, StoreName storeName, StoreLocation storeLocaion, string password, X509KeyStorageFlags x509KeyStorageFlags)
        {
            X509Store store = new X509Store(storeName, storeLocaion);
            try
            {
                bool Exists = false;
                X509Certificate2 cert = new X509Certificate2(certFileName, TranString.convertToSecureString(password), x509KeyStorageFlags);
                store.Open(OpenFlags.ReadWrite);
                foreach (X509Certificate2 storeCert in store.Certificates)
                {
                    if (storeCert.Thumbprint.Equals(cert.Thumbprint, StringComparison.OrdinalIgnoreCase))
                    {
                        Exists = true;
                        break;
                    }
                }
                if (!Exists)
                {
                    store.Add(cert);
                }
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                store.Close();
            }
        }

        private void InstallCertification(string certFileName, StoreName storeName, StoreLocation storeLocaion)
        {
            X509Store store = new X509Store(storeName, storeLocaion);
            try
            {
                bool Exists = false;
                X509Certificate2 cert = new X509Certificate2(certFileName);
                store.Open(OpenFlags.ReadWrite);
                foreach (X509Certificate2 storeCert in store.Certificates)
                {
                    if (storeCert.Thumbprint.Equals(cert.Thumbprint, StringComparison.OrdinalIgnoreCase))
                    {
                        Exists = true;
                        break;
                    }
                }
                if (!Exists)
                {
                    store.Add(cert);
                }
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                store.Close();
            }
        }

        private void DeleteCertification(string certFileName, StoreName storeName, StoreLocation storeLocaion, string password, X509KeyStorageFlags x509KeyStorageFlags)
        {
            X509Store store = new X509Store(storeName, storeLocaion);
            try
            {
                X509Certificate2 cert = new X509Certificate2(certFileName, TranString.convertToSecureString(password), x509KeyStorageFlags);
                store.Open(OpenFlags.ReadWrite);
                foreach (X509Certificate2 storeCert in store.Certificates)
                {
                    if (storeCert.Thumbprint.Equals(cert.Thumbprint, StringComparison.OrdinalIgnoreCase))
                    {
                        store.Remove(cert);
                        break;
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                store.Close();
            }
        }

        private void DeleteCertification(string certFile, StoreName storeName, StoreLocation storeLocaion)
        {
            X509Store store = new X509Store(storeName, storeLocaion);
            try
            {
                X509Certificate2 cert = new X509Certificate2(certFile);
                store.Open(OpenFlags.ReadWrite);
                foreach (X509Certificate2 storeCert in store.Certificates)
                {
                    if (storeCert.Thumbprint.Equals(cert.Thumbprint, StringComparison.OrdinalIgnoreCase))
                    {
                        store.Remove(cert);
                        break;
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                store.Close();
            }
        }



        private string GetCertHash(string certFileName)
        {
            using (X509Certificate2 cert = new X509Certificate2(certFileName))
                return cert.Thumbprint.ToLower();
        }

        private string GetAssemblyGuid()
        {
            var assembly = typeof(Program).Assembly;
            var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0];
            var id = attribute.Value;
            return id.ToLower();
        }

        private bool CertificationNetBind(string certFileName, string port)
        {
            StringBuilder sbPsiResults = new StringBuilder();
            ProcessStartInfo psi = new ProcessStartInfo() { CreateNoWindow = true, UseShellExecute = false, RedirectStandardOutput = true };
            bool isBounded = false;
                       
            // SHOW
            psi.FileName = "netsh";
            psi.Arguments = $"http show sslcert ipport=0.0.0.0:{port}";
            sbPsiResults.Clear();
            Process procHttpShow = Process.Start(psi);
            while (procHttpShow != null && !procHttpShow.StandardOutput.EndOfStream)
                sbPsiResults.Append(procHttpShow.StandardOutput.ReadLine());
            procHttpShow?.WaitForExit(2000);

            if (sbPsiResults.ToString().ToLower().Contains(GetCertHash(certFileName)) && sbPsiResults.ToString().ToLower().Contains(GetAssemblyGuid()))
            {
                // DELETE
                psi.FileName = "netsh";
                psi.Arguments = $"http delete sslcert ipport=0.0.0.0:{port}";
                sbPsiResults.Clear();
                Process procHttpDelete = Process.Start(psi);
                while (procHttpDelete != null && !procHttpDelete.StandardOutput.EndOfStream)
                    sbPsiResults.Append(procHttpDelete.StandardOutput.ReadLine());
                procHttpDelete?.WaitForExit(2000);

                if (sbPsiResults.ToString().ToLower().Contains("success"))
                    isBounded = false;
                else
                    throw new Exception($"http delete sslcert error : {sbPsiResults.ToString()}");
            }
            else
                isBounded = false;
            
            if (!isBounded)
            {
                // ADD
                psi.FileName = "netsh";
                psi.Arguments = $"http add sslcert ipport=0.0.0.0:{port} certhash={GetCertHash(certFileName).ToLower()} appid={{{GetAssemblyGuid()}}}";
                sbPsiResults.Clear();
                Process procHttpAdd = Process.Start(psi);
                while (procHttpAdd != null && !procHttpAdd.StandardOutput.EndOfStream)
                    sbPsiResults.Append(procHttpAdd.StandardOutput.ReadLine());
                procHttpAdd?.WaitForExit(2000);
                if (sbPsiResults.ToString().ToLower().Contains("error"))
                {
                    isBounded = false;
                    throw new Exception($"http add sslcert error : {sbPsiResults.ToString()}");
                }
                else
                    isBounded = true;
            }
            return isBounded;
        }
    }
}



Posted by 보미아빠
, |

secureString

2019. 11. 4. 16:51
보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GoFMemento
{
    class CareTaker
    {
        static void Main(string[] args)
        {
            List savedStates = new List();
            Originator originator = new Originator();
            originator.set("State1");
            originator.set("State2");
            savedStates.Add(originator.saveToMemento());
            originator.set("State3");
            savedStates.Add(originator.saveToMemento());
            originator.set("State4");
            originator.restoreFromMemento(savedStates[1]);
        }
    }

    class Originator
    {
        private string state; 
        public void set (string state)
        {
            this.state = state;
            Console.WriteLine("Originator: Setting state to " + state);
        }

        public Memento saveToMemento() // createMemento()
        {
            Console.WriteLine("Originator: Saving to Memento.");
            return new GoFMemento.Originator.Memento(this.state);
            // 예제에서는 string 이 쓰였는데, 실제로는 object 가 많이 쓰이니 serialize deserilize 를 이용하면 더 좋은 구현이 될 수 있다. 
        }

        public void restoreFromMemento (Memento memento) // restore (Memento)
        {
            this.state = memento.getSavedState();
            Console.WriteLine("Originator: State after restoring from Memento: " + state);
        }

        public sealed class Memento
        {
            private string state;
            public Memento (string stateToSave) // setState()
            {
                state = stateToSave; 
            }

            public string getSavedState() // getState()
            {
                return state; 
            }
        }
    }

}

Posted by 보미아빠
, |

대역폭 조절과 현재 프로세스의 네트워크 전송량 체크하기 (관리자모드로 실행할것)

WebStreamDownload.zip
2.25MB

Posted by 보미아빠
, |


create FUNCTION [dbo].[fnString2Base64Unicode]
(
    @STRING nVARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
    RETURN (
        SELECT
            CAST(N'' AS XML).value(
                  'xs:base64Binary(xs:hexBinary(sql:column("bin")))'
                , 'VARCHAR(MAX)'
            )   Base64Encoding
        FROM (
            SELECT CAST(@STRING AS VARBINARY(MAX)) AS bin
        ) AS bin_sql_server_temp
    )
END
GO

create FUNCTION [dbo].[fnBase64Unicode2String]
(
    @BASE64_STRING NVARCHAR(MAX)
)
RETURNS NVARCHAR(MAX)
AS
BEGIN

    RETURN (
        SELECT 
            CAST(
                CAST(N'' AS XML).value('xs:base64Binary(sql:variable("@BASE64_STRING"))', 'VARBINARY(MAX)') 
            AS NVARCHAR(MAX)
            )   UTF8Encoding
    )
END
go

select [dbo].[fnString2Base64Unicode](N'명령어')
select [dbo].[fnBase64Unicode2String]('hbo5uLTF')

Posted by 보미아빠
, |

최근에 달린 댓글

최근에 받은 트랙백

글 보관함