顯示具有 點網 標籤的文章。 顯示所有文章
顯示具有 點網 標籤的文章。 顯示所有文章

2025年12月8日 星期一

[點網]使用 openxml 從 CSV 檔轉成 excel 檔

僅供參考

參考網址:

 https://learn.microsoft.com/en-us/office/open-xml/spreadsheet/how-to-create-a-spreadsheet-document-by-providing-a-file-name

https://learn.microsoft.com/en-us/office/open-xml/getting-started

https://www.nuget.org/packages/DocumentFormat.OpenXml

https://blog.darkthread.net/blog/csvhelper/

https://www.cnblogs.com/geovindu/p/19161493


程式:

```

DataTable dataTable = ReadCsv(inputPath, encoding, delimiter);


ConvertDataTableToXls(dataTable, outputPath);


public static DataTable ReadCsv(string filePath, Encoding encoding, char delimiter)

        {

            try

            {

                using (var reader = new StreamReader(filePath, encoding))

                using (var csv = new CsvReader(reader, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture)

                {

                    Delimiter = delimiter.ToString(),

                    HasHeaderRecord = true,

                    IgnoreBlankLines = true,

                    TrimOptions = CsvHelper.Configuration.TrimOptions.Trim

                }))

                {

                    using (var dr = new CsvDataReader(csv))

                    {

                        var dt = new DataTable();

                        dt.Load(dr);

                        return dt;

                    }

                }

            }

            catch (Exception ex)

            {

                throw new Exception($"Failed to read CSV file: {ex.Message}", ex);

            }

        }


public static void ConvertDataTableToXls(DataTable dataTable, string outputPath)

        {

            try

            {

                // Create a new spreadsheet document

                using (SpreadsheetDocument document = SpreadsheetDocument.Create(outputPath, SpreadsheetDocumentType.Workbook))

                {

                    // Add a WorkbookPart to the document

                    WorkbookPart workbookPart = document.AddWorkbookPart();

                    workbookPart.Workbook = new Workbook();

 

                    // Add a WorksheetPart to the WorkbookPart

                    WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();

                    worksheetPart.Worksheet = new Worksheet(new SheetData());

 

                    // Add Sheets to the Workbook

                    Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());

 

                    // Append a new worksheet and associate it with the workbook

                    Sheet sheet = new Sheet()

                    {

                        Id = workbookPart.GetIdOfPart(worksheetPart),

                        SheetId = 1,

                        Name = "Sheet1"

                    };

                    sheets.Append(sheet);

 

                    // Get the SheetData object

                    SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();

 

                    // Add header row

                    Row headerRow = new Row();

                    foreach (DataColumn column in dataTable.Columns)

                    {

                        Cell cell = CreateCell(column.ColumnName, CellValues.String);

                        headerRow.AppendChild(cell);

                    }

                    sheetData.AppendChild(headerRow);

 

                    // Add data rows

                    foreach (DataRow row in dataTable.Rows)

                    {

                        Row dataRow = new Row();

                        foreach (var item in row.ItemArray)

                        {

                            CellValues cellType = GetCellValueType(item);

                            string cellValue = GetCellValueAsString(item, cellType);

                            Cell cell = CreateCell(cellValue, cellType);

                            dataRow.AppendChild(cell);

                        }

                        sheetData.AppendChild(dataRow);

                    }

 

                    // Save the workbook

                    workbookPart.Workbook.Save();

                }

            }

            catch (Exception ex)

            {

                throw new Exception($"Failed to create XLS file: {ex.Message}", ex);

            }

        }


        private static Cell CreateCell(string value, CellValues cellType)

        {

            Cell cell = new Cell();

            cell.DataType = new EnumValue<CellValues>(cellType);

            cell.CellValue = new CellValue(value);

            return cell;

        }

        

        private static CellValues GetCellValueType(object value)

        {

            if (value == DBNull.Value)

                return CellValues.String;

 

            Type type = value.GetType();

 

            if (type == typeof(int) || type == typeof(long) || type == typeof(short) || type == typeof(byte))

                return CellValues.Number;

            else if (type == typeof(float) || type == typeof(double) || type == typeof(decimal))

                return CellValues.Number;

            else if (type == typeof(DateTime))

                return CellValues.Date;

            else if (type == typeof(bool))

                return CellValues.Boolean;

            else

                return CellValues.String;

        }


         private static string GetCellValueAsString(object value, CellValues cellType)

        {

            if (value == DBNull.Value)

                return string.Empty;

 

            switch (cellType)

            {

                case CellValues.Boolean:

                    return (bool)value ? "1" : "0";

                case CellValues.Date:

                    DateTime dateValue = (DateTime)value;

                    // Excel stores dates as OLE Automation dates

                    return dateValue.ToOADate().ToString(CultureInfo.InvariantCulture);

                case CellValues.Number:

                    return Convert.ToString(value, CultureInfo.InvariantCulture);

                default:

                    return Convert.ToString(value);

            }

        }

```

2024年11月11日 星期一

[csharp]發生 Managed Debugging Assistant 'NonComVisibleBaseClass' 錯誤

 我不知道原因,但只知道解法。從解法來看,是 VS IDE 管太多卡到舊DLL了。


In Visual Studio 2019: 

Debug Menu, Windows --> Exception settings, opens the Exception settings window. 

There expand "Managed Debugging Assistants" and finally uncheck NonComVisibleBaseClass


參考:

https://stackoverflow.com/questions/1049742/noncomvisiblebaseclass-was-detected-how-do-i-fix-this

2022年6月15日 星期三

[MSMQ]remote queue receive 遠端佇列接收

 快速說結論

在 Queue Server 端的設定 (Windows 10, Windows Server 2012R2 在 Workgroup 下測試通過)



然後 Guset 帳號不要開,Guset 帳號不要開,Guset 帳號不要開。

防火牆要注意一下。

就這樣。

其他更詳細的過程,有空再補充。


http://nthrbldyblg.blogspot.com/2017/02/msmq-between-two-computers.html


https://docs.microsoft.com/zh-tw/archive/blogs/johnbreakwell/understanding-how-msmq-security-blocks-rpc-traffic


https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms699854(v=vs.85)?redirectedfrom=MSDN

2021年5月24日 星期一

[點網]小技巧 想讓編譯出來的二進位檔固定

 在 source code 不變的情況下,使得 build binary 要一樣的話,dotnet 編譯參數可以用這個

deterministic = true

參考:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/code-generation

2019年1月16日 星期三

[點網] 非同步程式模型簡介

# 點網的異步程式模型

## 前言

從現在回頭看,還存在 .NET 裡面的非同步模型有三種:
* Event-based Asynchronous Model(EAM): methods + event handlers
* Asynchronous Programming Model(APM): Begin + End methods + IAsyncResult
* Task-based Asynchronous Programming(TAP) Model:Task object + (async/await)

在更早之前的就先跳過不討論。從這三種來看看差異在哪裡。

## Event-based Asynchronous Model(EAM)

第一種在 System.Net.WebClient 還看得到,例如,它使用 DownloadDataAsync 與 DownloadDataCompleted 來完成非同步操作。

```
public partial class Form1 : Form
{
    System.Net.WebClient webClient;
    public Form1()
    {
        InitializeComponent();
        webClient = new System.Net.WebClient();
        webClient.DownloadDataCompleted += WebClient_DownloadDataCompleted;
        webClient.DownloadDataAsync(new Uri("http://www.google.com"), "[form constructor trigger]");
        Debug.WriteLine("[form constructor]");
    }

    private void WebClient_DownloadDataCompleted(object sender, System.Net.DownloadDataCompletedEventArgs e)
    {
        Debug.WriteLine((string)e.UserState);
        Debug.WriteLine(BitConverter.ToString(e.Result));
    }
}
```
首先要先註冊 DownloadDataCompleted 發生時,要用自己寫的哪個函式來處理,範例中是用WebClient_DownloadDataCompleted 來接。當我們呼叫完 DownloadDataAsync 之後,就是等待事情做完,然後 WebClient_DownloadDataCompleted 會被某個 thread 呼叫執行,我們要做的事情就是在這裡寫好。如果有需要分辨不同需求的 DownloadDataAsync 所產生的 WebClient_DownloadDataCompleted,則可以把資訊放在 DownloadDataAsync 的第二個參數,由 e.UserState 拿回攜帶的資訊。
"[form constructor]" 在網頁內容之前就先寫出來,代表不是 blocking。

## Asynchronous Programming Model(APM)

第二種,則在新一點的物件中出現,像是 System.Net.WebRequest。例如,它使用 BeginGetResponse 與 AsyncCallback 這種 delegate callback 合體使用。

```
    public Form1()
    {
        InitializeComponent();
        System.Net.WebRequest webRequest = System.Net.WebRequest.Create("http://www.google.com");
        webRequest.BeginGetResponse(new AsyncCallback(
            (IAsyncResult ar) =>
            {
                System.Net.WebRequest req = (System.Net.WebRequest)ar.AsyncState;
                System.Net.WebResponse resp = req.EndGetResponse(ar);
                long cl = resp.ContentLength;
                byte[] buffer = new byte[cl];
                resp.GetResponseStream().Read(buffer, 0, (int)cl);
                Debug.WriteLine(BitConverter.ToString(buffer));
            }
            ), webRequest);
        Debug.WriteLine("[form constructor]");
    }
```
使用上,在 BeginGetResponse 把 callback 一同放進呼叫參數裡,我在這裡故意使用箭頭函式寫法,這樣可以顯出與 EAM 的不同。關注點就不同跳開在程式碼太遠的地方。當然也可以先準備好一個函式,呼叫 BeginGetResponse 時放進去。這樣的程式長像就會類似 EAM。像這樣,BeginGetResponse 與 callback 的對應就不容易錯亂。callback 攜帶資訊的地方在 BeginGetResponse 的第二個參數,callback 裡則用 ar.AsyncState 拿回來。

## Task-based Asynchronous Programming(TAP) Model

第三種又在新一點,它在 System.Net.Http.HttpClient 有用到。例如它使用 GetAsync 拿到 Task 物件,再利用 task 的操作拿到想要的內容。

```
    public Form1()
    {
        InitializeComponent();
        System.Net.Http.HttpClient httpClient;
        httpClient = new System.Net.Http.HttpClient();
        Task<System.Net.Http.HttpResponseMessage> taskHttpResponseMessage = httpClient.GetAsync("http://www.google.com");
        taskHttpResponseMessage.ContinueWith(new Action<Task<System.Net.Http.HttpResponseMessage>>(
            (Task<System.Net.Http.HttpResponseMessage> t) =>
            {
                System.Net.Http.HttpResponseMessage httpResponseMessage = taskHttpResponseMessage.Result;
                byte[] c = httpResponseMessage.Content.ReadAsByteArrayAsync().Result;
                Debug.WriteLine(BitConverter.ToString(c));
            }
            ));
        Debug.WriteLine("[form constructor]");
    }
```
在這裡,GetAsync 拿到 Task 物件,然後在 ContinueWith 裡使用箭頭函式處理呼叫成功之後該做什麼事。這樣子寫,程式看起來還像是 APM 的樣子,但是 Task 物件有自己攜帶 wait 之類的方法,在控制要不要 blocking 的時候更自由。

## Task-based Asynchronous Programming(TAP) Model + async/await

TAP 模式寫起來還是很像 APM 模式,多層疊或是流程長的話,程式碼也還是不容易看。但是在 async/await 修飾字出現之後,程式碼就好看很多。其原理僅是靠編譯器幫忙。由於 async/await 無法在 constructor 使用,我程式移到一個 getPage() 驅動。上面的例子就變得跟同步程式長得很像。

```
    public Form1()
    {
        InitializeComponent();
        getPage();
        Debug.WriteLine("[form constructor]");
    }

    async void getPage()
    {
        System.Net.Http.HttpClient httpClient;
        httpClient = new System.Net.Http.HttpClient();
        System.Net.Http.HttpResponseMessage httpResponseMessage = await httpClient.GetAsync("http://www.google.com");
        byte[] c = httpResponseMessage.Content.ReadAsByteArrayAsync().Result;
        Debug.WriteLine(BitConverter.ToString(c));
    }
```

## 總結

有時候會看到上面三述方法混和提供的物件,以後就可以按照需要自由取用。就功能來說這三種做法可以互相取代。當然以團隊來說,可以自己決定的話,就統一一種會比較好。

## 參考

* https://docs.microsoft.com/zh-tw/dotnet/standard/asynchronous-programming-patterns/index

* https://www.infoq.com/articles/Tasks-Async-Await

2019年1月3日 星期四

[點網] Asynchronous Programming Model(APM) 改成 blocking 模式

需求就是要把 BeginInvoke + EndInvoke + IAsyncResult 這種非同步模式改成同步模式。
似乎應該說是阻塞(Blocking)模式。

需要的是用到 System.Threading.AutoResetEvent 這個物件。
注意 signal.Set() 與 signal.WaitOne() 的位置
還有 signal 宣告的範圍

        byte[] ReadTheFile(string filepath)
        {
            var signal = new AutoResetEvent(false);
            var buf = new byte[1024];
            var stream = File.OpenRead(filepath);
            int readCount = 0;
            stream.BeginRead(buf, 0, buf.Length, new AsyncCallback(asyncResult =>
            {
                FileStream myStream = (FileStream)asyncResult.AsyncState;
                readCount = myStream.EndRead(asyncResult);
                signal.Set();
            }), stream);
            signal.WaitOne();
            stream.Dispose();
            var result = new byte[readCount];
            buf.CopyTo(result, 0);
            return result;
        }

我這麼做的原因是想把只有 APM 的改成 TAP,先把 APM 改成 block 再改成 TAP。也許將來有更好的方法。

2018年12月25日 星期二

[點網] .NET 的擴充方法

.NET 的 擴充方法 (C#/VB.NET)

https://docs.microsoft.com/zh-tw/dotnet/visual-basic/programming-guide/language-features/procedures/extension-methods

https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

不用繼承,也不用改變原始程式的情況下,替類別新增新的方法。

## VB .NET
要 Imports System.Runtime.CompilerServices 。
要在 Module 宣告。若要給 dll 外部使用,Module 要宣告 Public。
要擴充的方法上面要加上 <Extension()>,該方法或函式的第一個參數就是要擴充的型別。
可擴充的型別有:
  類別 (參考類型)
  結構 (實值類型)
  介面
  委派
  ByRef 和 ByVal 引數
  泛型方法的參數
  陣列

## C#
要定義在 static 物件中的 static 方法。
方法的第一個參數要加上 this 型別。
擴充方法是定義成靜態方法,但透過執行個體方法語法呼叫。

2018年9月25日 星期二

[點網][超速譯]VS2017 的中斷點

https://blogs.msdn.microsoft.com/visualstudio/2018/09/13/how-can-i-pause-my-code-in-visual-studio-breakpoints-faq/

Visual Studio 是我用過最好用的 IDE,沒有之一。
中斷點這件事也是我看過不少碼農不甚使用的事。正好有官方提出一些小技巧給大家知道。
快速摘譯重點,成為超速譯的一篇。


設立 breakpoint

(1)左點左邊界 或是 按F9
(2)按F5

管理 breakpoint

(1)breakpoint window
(2) Debug -> Window -> Breakpoints

Conditional Breakpoint

(1)設定 breakpoint
(2)鼠標飄到 breakpoint 上,按下齒輪圖示
(3)選擇 Conditions,然後設定條件
(4)條件輸入完畢,關閉設定窗

Iteration breakpoint

(1)設定 breakpoint
(2)鼠標飄到 breakpoint 上,按下齒輪圖示
(3)選擇 Conditions,然後設定條件為 Hit Count


Function breakpoint

(1) Debug -> New Breakpoint -> Break at Function


Value change breakpoint

* C++, data breakpoints
* Watch Window or the Breakpoints Window 右點 變數 選擇 Break when value changes
* managed code, 針對某個 instance 的屬性偵測改變
(1)在 break mode,右點物件選擇 Make Object ID
(2)在欲偵測的屬性 setter 加入一個 conditional breakpoint 條件是 this == $1
(3)按F5,會停在 setter
(4)在 Call Stack 雙點前一個 frame 可以看到改變屬性的 code 是哪一行


exception breakpoint

在 Exception Settings 窗,設定哪些 exception 要停下來


call stack breakpoint

(1)Debug -> Windows -> Call Statck
(2)右點 calling function,選擇 Breakpoint -> Insert Breakpoint


disassembly breakpoint

(1)打開 disassembly window, Debug -> Windows -> Disassembly
(2)左點左邊界或按F9

2018年9月12日 星期三

[點網] process.MainWindowHandle == 0


## 原因
為了拿到 process 的 MainWindowHandle 作隱藏/顯示。
但是在隱藏之後,process 的 MainWindowHandle 會等於 0


## 使用 AttachConsole GetConsoleWindow FreeConsole
其中一個方法是針對 console app 的作法是接到 console,拿到其 consolewindow 要到 ID,再離開。
使用 AttachConsole GetConsoleWindow FreeConsole

宣告需要:
```
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool FreeConsole();
int GetSmsdMainWindowHandle(int procID)
    Int32 tryHandle = 0;
    try
    {
        AttachConsole((uint)procID);
        tryHandle = GetConsoleWindow().ToInt32();
        FreeConsole();
    }
    catch (Exception)
    {
        //pass
    }
    finally
    {
        FreeConsole();
    }
    return tryHandle;
}
```

使用方法:
```
int smsdMainWindowHandle = GetSmsdMainWindowHandle(xProc.Id);
```


## 使用 EnumChildWindows GetWindowThreadProcessId
另一個方法是列舉所有 子window 再拿到其 window thread 的 process ID。
使用 EnumChildWindows GetWindowThreadProcessId

宣告需要:
```
private struct SearchData
{
    // You can put any vars in here...         
    public int currentTaskID;
    public IntPtr currenthWnd;
}
private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData data);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, ref SearchData data);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId);
bool EnumProc(IntPtr hWnd, ref SearchData data)
{
    int lProcID;
    GetWindowThreadProcessId(hWnd,out lProcID);
    if (lProcID == data.currentTaskID)
    {
        data.currenthWnd = hWnd;
    }
    return true;
}
```

使用方法:
```
SearchData n = new SearchData();
n.currentTaskID = xProc.Id;
EnumChildWindows(IntPtr.Zero,new EnumWindowsProc(EnumProc),ref n);
int smsdMainWindowHandle = (int)n.currenthWnd;
```

這個方法的 VB Code 由 Cyrus 提供:
```
Dim currenthWnd = 0
Public Function fEnumWindowsCallback(ByVal hWnd As Integer, ByVal lpData As Integer) As Integer
    fEnumWindowsCallback = 1
    Dim lProcID As Integer
    Call GetWindowThreadProcessId(hWnd, lProcID)
    If lProcID = currentTaskID Then
        currenthWnd = hWnd
    End If
End Function

Call EnumChildWindows(0&, AddressOf fEnumWindowsCallback, 0&)
If currenthWnd <> 0 Then
    If goSECSInterface.GEMObject.HideSMSD = True Then
        ShowWindow(currenthWnd, SW_HIDE)
    Else
        ShowWindow(currenthWnd, SW_NORMAL)
    End If
End If
```

## 參考:

  • * https://stackoverflow.com/questions/8949652/do-windows-api-enumwindows-and-enumchildwindows-functions-behave-differently-in