static void Main()
{
//load resource dll
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmTDSCreator());
}
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string resourceName = "TDSCreator.Resources." + new AssemblyName(args.Name).Name + ".dll";
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
byte[] assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
}
上色
Code Block
2018年6月28日 星期四
[.Net] Embedded dll into exe
1. Add dll to resources, set the build action to "embedded resources"
2. Add following code to "Program.cs"
2016年6月3日 星期五
[.Net] 讀取CSV出現亂碼
當CSV檔中含有中文時,使用StremReader讀取通常都會出現亂碼,這是因為.Net預設使用Unicode編碼,但通常Excel還是使用Big5編碼,此時只要以下列方式指定系統編碼即可解決;
System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite); System.IO.StreamReader sr = new System.IO.StreamReader(fs, System.Text.Encoding.Default);使用System.Text.Encoding.Default指定系統預設編碼為StremReader的編碼格式。
[.Net] 字串轉為DateTime
通常需要將字串轉為DateTime的時候,一大問題就是來源格式常常不是固定的格式,而是有各種五花八門的格式,這時候就可以利用以下方式進行轉換:
首先定義可能出現的各種日期格式,可參照https://msdn.microsoft.com/en-us/library/8kb3ddd4(VS.71).aspx
接著就可以開始處理字串,使用CultureInfo.InvariantCulture解析不同國家語言格式的字串(或是套用目前的國家地區設定解析,CultureInfo.CurrentCulture),使用DateTimeStyles.AllowWhiteSpaces避免字串中可能出現的無意義空白;此外為了避免依然轉換錯誤,可以將整段敘述加入到Try...Catch區塊中,再於Catch區塊中對轉換錯誤加以處理。
Ref: https://dotblogs.com.tw/chhuang/2008/03/18/1921
首先定義可能出現的各種日期格式,可參照https://msdn.microsoft.com/en-us/library/8kb3ddd4(VS.71).aspx
string[] dateTimeList = {
"yyyy/M/d tt hh:mm:ss",
"yyyy/MM/dd tt hh:mm:ss",
"yyyy/MM/dd HH:mm:ss",
"yyyy/M/d HH:mm:ss",
"yyyy/M/d",
"yyyy/MM/dd",
"M/d HH:mm:ss"
};
接著就可以開始處理字串,使用CultureInfo.InvariantCulture解析不同國家語言格式的字串(或是套用目前的國家地區設定解析,CultureInfo.CurrentCulture),使用DateTimeStyles.AllowWhiteSpaces避免字串中可能出現的無意義空白;此外為了避免依然轉換錯誤,可以將整段敘述加入到Try...Catch區塊中,再於Catch區塊中對轉換錯誤加以處理。
string DateTime date;
try
{
date = DateTime.ParseExact(dateString, dateTimeList, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces);
transferFlag = true;
}
catch (Exception e)
{
throw new Exception("日期格式錯誤: " + e.Message);
}
Ref: https://dotblogs.com.tw/chhuang/2008/03/18/1921
2016年2月1日 星期一
[Android] Android 6.0 (marshmallow) run-time permission 執行期間權限取得
自Android 6.0開始,除了必須在AndroidManifest.xml中宣告權限,在安裝時告知使用者外,執行期間需要用到特殊權限的話也必須告知使用者並取得。
權限可區分為以下兩大類
若要確認是否具有權限,可使用
而當使用者拒絕授予此權限時,開發者可能會需要說明該權限的用途並再次詢問,這時可使用
Reference: Android developer documents
權限可區分為以下兩大類
- 一般權限(PROTECTION_NORMAL),亦即在AndroidManifest.xml中宣告即可,在程式安裝時即授予程式該權限,用戶也無法手動取消。在Android 6.0(API 23)中,一般權限列表如下︰
- ACCESS_LOCATION_EXTRA_COMMANDS
- ACCESS_NETWORK_STATE
- ACCESS_NOTIFICATION_POLICY
- ACCESS_WIFI_STATE
- BLUETOOTH
- BLUETOOTH_ADMIN
- BROADCAST_STICKY
- CHANGE_NETWORK_STATE
- CHANGE_WIFI_MULTICAST_STATE
- CHANGE_WIFI_STATE
- DISABLE_KEYGUARD
- EXPAND_STATUS_BAR
- GET_PACKAGE_SIZE
- INTERNET
- KILL_BACKGROUND_PROCESSES
- MODIFY_AUDIO_SETTINGS
- NFC
- READ_SYNC_SETTINGS
- READ_SYNC_STATS
- RECEIVE_BOOT_COMPLETED
- REORDER_TASKS
- REQUEST_INSTALL_PACKAGES
- SET_TIME_ZONE
- SET_WALLPAPER
- SET_WALLPAPER_HINTS
- TRANSMIT_IR
- USE_FINGERPRINT
- VIBRATE
- WAKE_LOCK
- WRITE_SYNC_SETTINGS
- SET_ALARM
- INSTALL_SHORTCUT
- UNINSTALL_SHORTCUT
- 需要執行期間授權的權限,用戶也可以在設定中隨時關閉他們,Android將之分為數個類別,當取得類別中的其中一個權限時,也就等於取得該類別所有權限,分類如下︰

ActivityCompat.requestPermissions(Activity activity, String[] permissions, int requestCode)
若要確認是否具有權限,可使用
ContextCompat.checkSelfPermission (Context context, String permission)
而當使用者拒絕授予此權限時,開發者可能會需要說明該權限的用途並再次詢問,這時可使用
ActivityCompat.shouldShowRequestPermissionRationale(Activity activity, String permission)
當使用者拒絕授予權限時,下次調用此函式就會返回true,開發者可在此時加入權限說明。
當使用者選擇授予或拒絕此權限時,會呼叫onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)方法,此時override此方法即可處理需要權限的操作。
當使用者選擇授予或拒絕此權限時,會呼叫onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)方法,此時override此方法即可處理需要權限的操作。
具體程式碼如下(以讀寫SD卡為例)︰
private final int REQUEST_CODE_ASK_PERMISSIONS = 10;
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE_ASK_PERMISSIONS:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted
//執行需要讀寫SD卡的操作
} else {
// Permission Denied
Toast.makeText(MainActivity.this, getString(R.string.noPermission), Toast.LENGTH_LONG).show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
private void checkPermission(){
//讀取關於讀寫外部儲存裝置的權限
int hasReadExternalStoragePermission = ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
//若沒有權限則詢問取得
if (hasReadExternalStoragePermission!= PackageManager.PERMISSION_GRANTED)
{
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,Manifest.permission.WRITE_EXTERNAL_STORAGE)){
//當被使用者拒絕後再次詢問時,說明該權限用途,用戶可選擇重試(重新詢問是否授予)或取消(維持不授予權限)
new AlertDialog.Builder(MainActivity.this)
.setMessage("該權限用以讀寫SD卡")
.setPositiveButton("重試", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE_ASK_PERMISSIONS);
}
})
.setNegativeButton("取消", null)
.create()
.show();
return;
}
ActivityCompat.requestPermissions(MainActivity.this,new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},REQUEST_CODE_ASK_PERMISSIONS);
}
else
//已有權限,直接執行需要讀寫SD卡的操作
}
Reference: Android developer documents
2015年12月14日 星期一
[Android] 偵測方向使用不同layout
若要偵測使用者螢幕方向,並使用對應不同xml的layout,可使用下列方式︰
- 設計兩種不同layout的xml檔案。
- 在AndroidManifest.xml中要改變的activity中新增屬性︰
- 如此一來當方向或螢幕大小改變的時候,就會觸發︰
onConfigurationChanged(Configuration newConfig)
- 依照類似下面的方式判斷長寬,以決定適用的layout file。
public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); Display display = getWindowManager().getDefaultDisplay(); int width; int height; Point size = new Point(); display.getSize(size); width=size.x; height=size.y; if (width>height) { //Landscape setContentView(R.layout.activity_main_land); initView(); } else{ setContentView(R.layout.activity_main_port); initView(); } }
android:configChanges="orientation|keyboardHidden|screenSize"
2015年12月11日 星期五
[Android] Shell Tool for root commands
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Scanner;
import android.content.res.AssetManager;
import android.os.Build;
import android.util.Log;
public class ShellUtils
{
private static String busyboxPath="/system/xbin/busybox";
/**
* Set custom busybox path
* @param path Path
*/
public static void setCustomBusybox(String path){
busyboxPath = path;
}
public static boolean checkBusyboxPath(){
try{
if (!new File("/system/xbin/busybox").exists()){
if(!new File("/system/bin/busybox").exists())
return false;
else busyboxPath="/system/bin/busybox";
}
else busyboxPath="/system/xbin/busybox";
}catch (SecurityException e){
return false;
}
return true;
}
/**
* Try to get root permission
* @return true means success; false means fail
*/
public static boolean rootCheck(){
//List all the files under "/data/data", doing this operation needs root permission
//CommandResult commandResult = execCommand(false,true, "ls /data/data/");
//Empty result means there's no root permission
//return !commandResult.successMsg.isEmpty();
return execCommand(false,true,"").result==0;
}
@SuppressWarnings("deprecation")
public static boolean initiateBusybox(){
//Clear old files
File busybox = new File(GlobalVariable.getContext().getFilesDir()+"/busybox");
if (busybox.exists())
busybox.delete();
//Copy corresponding busybox to internal folder
String cpuVersion;
if (android.os.Build.VERSION.SDK_INT <21)
cpuVersion= Build.CPU_ABI;
else
cpuVersion=Build.SUPPORTED_ABIS[0];
//Determine busybox version
String filename;
cpuVersion=cpuVersion.toLowerCase();
if (cpuVersion.contains("arm"))
filename="busybox-armv5l";
else if (cpuVersion.contains("x86"))
filename="busybox-i686";
else
return false;
AssetManager assetManager = GlobalVariable.getContext().getAssets();
InputStream in = null;
OutputStream out = null;
try {
in = assetManager.open(filename);
out = new FileOutputStream(busybox);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
catch (IOException e) {
e.printStackTrace();
return false;
}
finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//Make busybox executables
ShellUtils.execCommand(false, true, "chmod 0755 " + GlobalVariable.getContext().getFilesDir() + "/busybox");
return true;
}
/**
* Execute commands and get the results
* @param isBusybox Run cmds via busybox or not
* @param isRoot Run cmds as root?
* @param cmds Command(s)
* @return Results of commands
*/
public static CommandResult execCommand(boolean isBusybox, boolean isRoot, String...cmds){
int result=-1;
StringBuilder successMsg = null;
StringBuilder errorMsg = null;
if (cmds==null || cmds.length==0)
return new CommandResult(result,null,null);
try{
Process proc=Runtime.getRuntime().exec(isRoot?"su":"sh");
DataOutputStream opt = new DataOutputStream(proc.getOutputStream());
boolean exitCmdFound=false;
//Write cmds
for(String cmd:cmds){
//Using busybox and check its path
if (isBusybox)
opt.writeBytes(busyboxPath + " ");
//Unless make sure cmd is in English, using UTF-8 coding, avoid wrong coding.
opt.write(cmd.getBytes(Charset.forName("utf-8")));
if(!exitCmdFound && cmd.equals("exit"))
exitCmdFound=true;
opt.writeBytes("\n");
}
if(!exitCmdFound)
opt.writeBytes("exit\n");
opt.flush();
//Get results
result=proc.waitFor();
successMsg = new StringBuilder();
errorMsg = new StringBuilder();
Scanner scanner;
scanner=new Scanner(new InputStreamReader(proc.getInputStream()));
while (scanner.hasNextLine())
successMsg.append(scanner.nextLine());
scanner=new Scanner(new InputStreamReader(proc.getErrorStream()));
while (scanner.hasNextLine())
errorMsg.append(scanner.nextLine());
} catch (Exception e){
e.printStackTrace();
}
return new CommandResult(result,successMsg==null?null:successMsg.toString(), errorMsg==null?null:errorMsg.toString());
}
public static class CommandResult {
/**
* Result of command
* 0: normal
* else: error
*/
public int result;
public String successMsg;
public String errorMsg;
public CommandResult(int result, String successMsg, String errorMsg) {
this.result = result;
this.successMsg = successMsg;
this.errorMsg = errorMsg;
}
}
}
2015年7月31日 星期五
[C#] Load custom cursor from resources
Sometime you need a custom cursor for your application, the following step let you use your custom cursor in the resources.
- Add cursor files (*.cur) to resources
- In [Properties] -> [Resources] tab, click [Add Resource] -> [Add Existing File...]
- Choose your custom cursors and click OK.
- Load cursor with following code:
this.Cursor = new Cursor(new System.IO.MemoryStream(Properties.Resources.MyCursor));, where Mycursor refers to your cursor name.
訂閱:
文章 (Atom)