.udl (Universal Data Link) 實為 **Unicode 文字檔**,內容結構:
[oledb]
; Everything after this line is an OLE DB initstring
Provider=SQLOLEDB.1;Password=xxx;Persist Security Info=True;User ID=yyy;Initial Catalog=zzz;Data Source=server
關鍵限制:檔案開頭必須為 **BOM (Byte Order Mark) 0xFEFF**,否則 ADO 無法辨識。
struct DBParam {
char Server[20];
char Database[20];
char UserId[20];
char Password[20];
};
class CUdlFile {
DBParam m_dbParameter;
public:
BOOL CreateUdlFile(LPCTSTR lpFileName);
BOOL DeleteUdlFile(LPCTSTR lpFileName);
};
BOOL CUdlFile::CreateUdlFile(LPCTSTR lpFileName) {
CFile fUdl;
if (!fUdl.Open(lpFileName, CFile::modeCreate | CFile::modeWrite))
return FALSE;
// 1. 寫入 BOM (0xFEFF)
WCHAR bom = 0xFEFF;
fUdl.Write(&bom, sizeof(WCHAR));
// 2. 寫入固定標頭 (Unicode)
fUdl.Write(L"[oledb]", 14); // 7 字元 * 2 bytes
fUdl.Write(L"\r\n", 4); // 2 字元 * 2 bytes
fUdl.Write(L"; Everything after this line is an OLE DB initstring", 104); // 52 字元 * 2
fUdl.Write(L"\r\n", 4);
// 3. 格式化連線字串 (ANSI -> Unicode)
CString s3;
s3.Format(_T("Provider=SQLOLEDB.1;Password=%s;Persist Security Info=True;User ID=%s;Initial Catalog=%s;Data Source=%s"),
m_dbParameter.Password, m_dbParameter.UserId,
m_dbParameter.Database, m_dbParameter.Server);
int m_Length = s3.GetLength();
LPWSTR m_Buffer = (LPWSTR)malloc((m_Length + 1) * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, s3, m_Length, m_Buffer, m_Length);
fUdl.Write(m_Buffer, m_Length * 2); // 字元數 * 2 bytes
free(m_Buffer);
fUdl.Write(L"\r\n", 4);
fUdl.Close();
return TRUE;
}
BOOL CUdlFile::DeleteUdlFile(LPCTSTR lpFileName) {
return ::DeleteFile(lpFileName);
}
| 陷阱 | 症狀 | 解法 |
|---|---|---|
| 忘記寫入 BOM | OpenUDLFile 失敗,錯誤「無效的連線字串」 | 首寫 0xFEFF |
| 用 CStdioFile 寫入 | 預設為 ANSI,無 BOM | 用 CFile 二進位模式 + MultiByteToWideChar |
| Write 長度誤算 | 檔案截斷或亂碼 | 字元數 * sizeof(WCHAR) = *2 |
| 連線字串含特殊字元 | 解析錯誤 | 密碼含分號/等號時需雙引號包裹 |
CUdlFile udl;
udl.m_dbParameter.Server = _T("192.168.1.100");
udl.m_dbParameter.Database = _T("ERP");
udl.m_dbParameter.UserId = _T("sa");
udl.m_dbParameter.Password = _T("P@ssw0rd");
CString udlPath = _T("C:\\Temp\\Runtime.udl");
if (udl.CreateUdlFile(udlPath)) {
CAdoConnection conn;
if (conn.OpenUDLFile(udlPath)) {
// 連線成功,可直接操作
}
// 用完可刪除
udl.DeleteUdlFile(udlPath);
}
適合:安裝程式自動配置、多資料庫切換、避免硬編碼連線字串、部署時由使用者輸入參數產生專屬 UDL。