Tuesday, April 24, 2018

Android soundtouch jni引用

準備,最近網友問問題,變調要使用哪一種lib
soundtouch開始下載然後呢

裝完
讓我們
下載下來
https://www.jianshu.com/p/41e0e39031bb
照著這位大神作下來


然後呢跟大神不一樣加上這行
APP_ALLOW_MISSING_DEPS :=true



近來嚕

參考
https://blog.csdn.net/wkw1125/article/details/63807128
https://www.jianshu.com/p/41e0e39031bb

Monday, April 23, 2018

Android include source form github (exoplayer) add funaction

引用


當一個專案只能透過,但又想改裡面的函數怎麼辦?
下面會來用一個例子從引用到,修改其函數與新增
com.google.android.exoplayer:exoplayer-ui:r2.7.4

但是當你要修改裡面的源碼要怎麼辦呢?

Java 反射調用(x)



反射調用可以訪問並且修改其private的變數與方法
public class Private
{
private String name = "张三";
private String getName()
{
return name;
}
}
package com.wangzhuo.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class PrivateTest
{
public static void main(String[] args)throws Exception
{
//获取Private类的Class对象
Class<?> classType = Class.forName("com.wangzhuo.reflect.Private");  <--目標如果是jar等等之類的
//获取其构造方法对应的Constructor对象
Constructor con = classType.getDeclaredConstructor(new Class[]{});
//创建Private的对象
Object object =con.newInstance(new Object[]{});
//获取Private类中name属性对应的Field对象
Field field = classType.getDeclaredField("name"); <--field是變數
//设置避开java访问控制检测
field.setAccessible(true);
//获取修改前的值
Object str = field.get(object);
System.out.println("修改之前name的值:"+(String)str);
//给name属性赋值
field.set(object, "李四");
//获取getName方法对应的Method对象
Method getNameMethod = classType.getDeclaredMethod("getName", new Class[]{}); <--Method是方法
//设置避开java访问控制检测
getNameMethod.setAccessible(true);
//调用方法,返回值
Object o = getNameMethod.invoke(object, new Object[]{});
System.out.println("修改之后name的值:"+(String)o);
}
}
----------------------------------------
mAudioTrack =null;
try
{
Class<?> bookClass = Class.forName("com.google.android.exoplayer2.audio.DefaultAudioSink");//完整类名
Log.i("qsss",bookClass.getSimpleName());
Object book = bookClass.newInstance();//获得实例
Field getAuthor = bookClass.getDeclaredField("audioTrack");//获得私有方法
getAuthor.setAccessible(true);//调用方法前,设置访问标志
mAudioTrack = (AudioTrack) getAuthor.get(book);//使用方法
}
catch (Exception e)
{
e.printStackTrace();
}
mAudioTrack.setStereoVolume(0f,1f);
失敗= = 可能要用下面方法引用在進行調用,才會成功改天再測試


這邊簡單帶過,知道有這方法就好,大家自己去研究

Github取得舊的原始碼





這邊就可以嚕~

新增一個funaction?


可不可行?當然可以 

https://github.com/google/ExoPlayer/
compile 'com.google.android.exoplayer:exoplayer:2.7.3   <--卡頓

https://github.com/yusufcakmak/ExoPlayerSample
compile 'com.google.android.exoplayer:exoplayer:r2.5.1  <--卡頓
找來找去還是一樣同一個source code,但是為什麼,後者執行沒問題,最新版執行卻是卡頓呢?
大家第一個反應可能是函數有問題,會先降等級所以我就先降等級

起初以為是build Tools version 有問題所以有四種可能性
套件版本有問題 編譯器版本過高
套件版本沒問題 編譯器版本過高
套件版本沒問題 編譯器版本正常
套件版本有問題 編譯器版本正常
這邊全部試下來發現
2.7.3編譯的時候 需要build Tools version為27 而且 compile 要改成implementation
r2.5.1編譯的時候 build Tools version預設為25 條至27 也沒問題 
初步判斷為 套件版本有問題
這樣看來我們是要用下面的r2.5.1做為開發的基底了



反射調用沒用的話怎麼辦?
這時候就要把源碼弄到本地端進行程式碼修改了

大家等級都很高我就不說怎樣調用了

path的資料夾地點
這時候我把r2.5.1,又生到了2.73 這時候很奇怪這個時候的話我在r2.51 build app 卻也沒發生問題?


為了求證我們把兩個版本替換到我總共替換兩個
2.73 失敗
2.6  成功
2.54 成功(不考慮後續會說位啥不用
引用成功後


小插曲
import com.google.android.exoplayer2.source xxx有一個hls的包遺失,我們把她槓掉就沒事了


當一個專案只能透過 
深入解析
當要修改別人的源碼呢,挖個link,上看千行怎麼辦?

這邊可以做整個資源的搜尋,我們可以透過這個搜尋我們要尋找的某個程式碼片段
大家可以看到我那時要開發一個升降key的,後來又發現要切換聲道,後來慢慢拆解後發現
她是透過一層一層呼叫,各種神呼叫





挖,要改到死诶,還不一定對,所以呢我們要盡量避開這種大改,我們小改就好
在不破壞原先結構的函數,我們盡量找小的地方改就好所以呢?

setVolume 我們就單弄這幾個函數就好
我們嘗試把它弄成
setVolume2






動這六個檔案,我們就可以產生一個函數了,為什麼要用這樣呢,因為我要改裡面
AudioTrack裡面有一個函數
原本是
setVolume(volume);
但是我要用下面的
setStereoVolume(volume, volume2);


可以切換左右聲道,需要傳遞兩個變數,可以看到
handleMessage(int messageType, Object message) throws ExoPlaybackException {
可能要改成
handleMessage(int messageType, Object message, Object message) throws ExoPlaybackException {


我以為Object可以傳遞陣列 結果也不行,懶得改的結果就想到了這個方法
那麼我只要
setVolume2(volume);
this.volume2=volume
存入class變數就好
-----------------------------
setVolume(volume);
this.volume=volume
的時候將會調用
setStereoVolume(volume, volume2);
這樣的話就可以切換左右聲道了

源碼就不提供囉,保密(o

為什麼不引用原先的r2.53的?





原先的缺少該目標DefaultAudioSink,沒辦法找到AudioTrack進行的修改

Monday, April 9, 2018

Android 工具人app

功能介紹


以前的課專,忘記上傳解說一波。





一個類似UBER的APP可以延伸運用
但是不向UBER只侷限開車也很像神奇寶貝GO的抓寶地圖



這APP打算用資料庫和GPS Or WIFI定位和GOOGLE MAP地圖
功能的基本:就是可以任意在地圖上留下訊息,在下面欄位那邊可以搜尋之前的人所留留下的訊息點擊該marker可以觀看在該點下更多訊息,搜尋提供直觀的你的位置到對方位置在你搜尋時可以動態的觀看到線該線可以很清楚的看到你與留下訊息的人的距離

功能


在地圖上點及任何一點,可以對該點設置你想說的話,將會插入一筆資料
此筆資料可以有你的姓名和你想留下的資料,系統會產生時間戳記到這筆
資料下方也有搜索欄位我們可以透過搜索欄位對所有留下資料的做搜尋,
而點擊下方搜索欄位將會產生一條線和移動至該點,在搜尋欄位中做搜尋
的話可以將繪畫多條線到目前你的位置,可以很直觀的看到位於你最近的
人或服務在哪。

如何呼叫mysql


Android 呼叫 網頁php 透過post將指令送出 到mysql,mysql 回傳資料json
則我們將對這串資料做處理。

重要功能


負責呼叫mysql 指令
製作動態搜尋,並畫線
為搜尋欄位新增監聽事件
Init()
searchitem(String textToSerch)
點擊地圖上marker則會顯示該點會下所有的訊息(可以該點多筆資料
點擊該點則會顯示該點座標位置。

query.php


<?php
error_reporting(E_ALL ^ E_DEPRECATED);
$db = mysql_pconnect("mysql.hostinger.com.hk","u769530028_map","-----")or die('error');
//$db = mysqli_connect("mysql.hostinger.com.hk","u769530028_map","------","u769530028_map")or die('error');
mysql_select_db("u769530028_map");
mysql_query("set names utf8");
$sql ="";
if (isset($_POST['query_string']))
{
$sql = $_POST['query_string'];
}
else
{ $sql = $_POST['query_string'];}//這邊取得android 傳過來的sql指令
$res = mysql_query($sql);
if($res === FALSE) {
die(mysql_error()); // TODO: better error handling
}
while($r = mysql_fetch_assoc($res))
$output[] = $r;
print(json_encode($output)); //轉成json格式 , android 會抓取整個頁面資烙
mysql_close();
?>
view raw qeury.php hosted with ❤ by GitHub


MapsActivity.java layout



MainActivity.java layout



負責呼叫mysql 指令


private String executeQuery(String query)
{
String result = "";
try
{
HttpClient httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost("http://x213212.esy.es/qeury.php");//如上面
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("query_string", query));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8));//防止亂馬
HttpResponse httpResponse = httpClient.execute(post);
HttpEntity httpEntity = httpResponse.getEntity();
InputStream inputStream = httpEntity.getContent();
BufferedReader bufReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"), 8);
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = bufReader.readLine()) != null)
{
builder.append(line + "\n");
}
inputStream.close();
result = builder.toString();//儲存所有頁面資料
}
catch (Exception e)
{
Log.e("log_tag", e.toString());
}
return result;//回傳
}
}


製作動態搜尋,並畫線


如果點擊所有訊息則將會將會去跟mysql取的資料,然後將取得的資料丟到list <string> list裡面
製作list搜尋欄位呢,我們要一個搜尋框,和所有資料,
我們將會回傳資料存到list然後必須在搜尋框那邊新增一個監聽事件。

回傳資料存到list


public final void renewListView(String input)
{
try
{
JSONArray jsonArray = new JSONArray(input);
list.clear();
setTitle(jsonArray.length() + "筆資料");
//tx1.setText(jsonArray.length() + "筆資料");
adapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1);
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject jsonData = jsonArray.getJSONObject(i); //一次讀一筆讀到尾
LatLng sydney = new LatLng(Float.valueOf( jsonData.getString("latitude")), Float.valueOf(jsonData.getString("longitude")));
mMap.addMarker(new MarkerOptions().position(sydney).title(jsonData.getString("name")) .snippet(jsonData.getString("data")));
adapter.add("name:"+jsonData.getString("name")+"\ndata:"+jsonData.getString("data") +"\nlocation["+jsonData.getString("longitude")+","+jsonData.getString("latitude")+"]\ntime:"+jsonData.getString("time"));//插入一筆到adapter
list.add("name:"+jsonData.getString("name")+"\ndata:"+jsonData.getString("data") +"\nlocation["+jsonData.getString("longitude")+","+jsonData.getString("latitude")+"]\ntime:"+jsonData.getString("time"));//插入一比到list string 型態
}
// adapter.add( );
ed1.setText("");//搜尋欄位清空
init();
lv1.setAdapter(adapter);//新增陣列到下方所有訊息
}
catch (JSONException e)
{
// TODO 自動產生的 catch 區塊
e.printStackTrace();
}
}


為搜尋欄位新增監聽事件


ed1.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if(s.toString().equals(""))
{
init();}
else
{searchitem(s.toString());
}
//如果使用者的搜尋框沒有東西的話則初始化,如果有東西則做篩選動作
}
@Override
public void afterTextChanged(Editable s) {
}
});


Init()


public void init ()
{
if(selectpolyline!=null)//把地圖上所有的線清除
{for(Polyline line : selectpolyline)
{
line.remove();
}
selectpolyline.clear();
}
list2 = new ArrayList<String>();//將list <string> list2
adapter2=new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1);
for(String s : list) {//這邊list已經將所有訊息裡面資料存進去了
adapter2.add(s);//為了讓listview 動態更新
list2.add(s);//新增一筆備份做沒有資料的時候還原
}
Toast.makeText(this, "ok", Toast.LENGTH_LONG).show();
lv1.setAdapter(adapter2);
}
view raw init.java hosted with ❤ by GitHub


searchitem(String textToSerch)


public void searchitem(String textToSerch)
{
try {
String[] stockArr = new String[list2.size()];//轉成string 陣列
stockArr = list2.toArray(stockArr);
for(String s : stockArr)
{
if(!s.contains(textToSerch))//如果再string s 裡面沒有找到跟 textToSerch 相關文字則從list2裡面移除
{
list2.remove(s);
}
}
//在一次adpter2做初始化
adapter2=new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1);
//這邊是第一次載入如果沒做搜尋則不會畫線
if(selectpolyline!=null)
{for(Polyline line : selectpolyline)
{
line.remove();
}
selectpolyline.clear();
}
//這時候可以發現list2裡面剩下的都是做過搜尋的東西
for(String s : list2) {
String tmp=s;
String subTest = tmp.substring(tmp.indexOf("location[")+9, tmp.indexOf("]"));
String[] latlong = subTest.split(",");
double latitude = Double.parseDouble(latlong[0]) ;
double longitude = Double.parseDouble(latlong[1]);
LatLng listtmp= new LatLng(longitude,latitude);
//youmarker 裡面會是程式碼一開始加載的時候透過或wifi裡面將會取得你目前位置
//這個迴圈裡面總共會有list2 x筆
// selectpolyline 一樣用list型態
selectpolyline.add( mMap.addPolyline(new PolylineOptions().
add(youmarker.getPosition(), listtmp).
width(10).//線寬度
color(Color.RED).//線顏色
geodesic(true)));
adapter2.add(s);
}
Toast.makeText(this, "搜尋完畢", Toast.LENGTH_LONG).show();
lv1.setAdapter(adapter2);//顯示
}catch(Exception e) {
Log.e("log_tag", e.toString());
}
}
view raw searchitem.java hosted with ❤ by GitHub


點擊地圖上marker則會顯示該點會下所有的訊息(可以該點多筆資料


public boolean onMarkerClick(Marker marker) {
//先做格式化在mysql裡面的double欄位裡面最多只可五位所以在精準度上最高到五位
tmp=marker.getPosition();
BigDecimal bd= new BigDecimal( tmp.longitude);
bd=bd.setScale(5, BigDecimal.ROUND_HALF_UP);// 小數後面四位, 四捨五入
BigDecimal bd2= new BigDecimal(tmp.latitude);
bd2=bd2.setScale(5, BigDecimal.ROUND_HALF_UP);// 小數後面四位, 四捨五入
String result = executeQuery("SELECT * FROM `test` WHERE `longitude` = "+bd+" AND `latitude` = "+bd2+"");
// tx1.setText(result);
renewListView(result);
Toast.makeText(getApplicationContext(),"Marker Clicked: " + bd2, Toast.LENGTH_LONG).show();
return false;
}


點擊該點則會顯示該點座標位置


public void onMapClick(LatLng latLng) {
if(marker!=null){
marker.remove();
touch=true;
tmp=latLng;
}
Toast.makeText(getApplicationContext(),"You touch: [" + latLng.latitude+","+latLng.longitude+"]", Toast.LENGTH_LONG).show();
marker = mMap.addMarker(new MarkerOptions().position(latLng).title("You touch here"));
}
view raw click_point hosted with ❤ by GitHub




Thursday, April 5, 2018

三系統共存之謎

kali linux + windows + mac


在大一的時候呢 我做了一個夢然後過程呢我的雲端硬碟出現一個網址
好像疑似工具包
然後呢我裝
我電腦架構是ge60 2pe
我裝的時候呢 grub 是用Clover grub 四葉草
然後我設定主系統windows 灌在uefi
然後切到legacy 先灌kali linux 
再切進去kali linux 做grub抹除動作好像有用到gpt 磁區重新規畫的東東
然後再去灌mac os 接下來 因為進去mac os 因為黑蘋果的話呢,我好像是用mac osx
然後呢 切進去 系統抓不到 系統顯示卡呢,所以分辨率會抓不到,這時候,可以透過
修改系統的config,FakeSMC 去修改驅動 之類的 ,那軟體好像是一根胡蘿波
修改完後 沒有wifi驅動放棄沒辦法,顯示卡驅動,你要先考慮cpu 在市面上
已經發售的蘋果電腦所使用的,cpu 這樣我們就可以透過修該config ,去詐欺系統
改顯示卡的型號,重新開機 進入四葉草grub就可以看到三系統啟動了 grub 那邊mac os
可能要修改一下系統啟動 參數詳情 因為夢太久忘了,等我心血來潮,說不定能再重新做一次呢。

Tuesday, April 3, 2018

c# Serial Arduino or Rs232

Serial Port 參數設定


下面程式碼將會將一個基本的傳輸程式碼介紹包括避開在面臨開發的一些難題,修正網路上程式碼可能會發生當機的地方加以修正。
那麼開始吧

直接上code惹


void setup() {
Serial.begin( 115200); // 開啟 Serial port, 通訊速率為 9600 bps
// 初始化 LED 接腳
pinMode(13, OUTPUT);
}
void loop() {
// 檢查是否有資料可供讀取
if (Serial.available() > 0) {
// 讀取進來的 byte
int i;
char inByte = Serial.read();
// 根據收到的字元決定要打開或關掉 LED
switch (inByte) {
case '0':
digitalWrite(13, LOW);
Serial.println("LED OFF");
break;
case '1':
digitalWrite(13, HIGH);
Serial.println("LED ON");
break;
case '2':
Serial.println("Connect ok!");
break;
case '3':
i = random(100);
Serial.println("test"+String(i));
break;
case '4':
i = random(2);
Serial.println("warring"+String(i));
break;
case '5':
Serial.println("Connect off!");
return ;
break;
default:
// 關掉所有的 LED
digitalWrite(13, LOW);
}
}
}
當傳輸資料突然發生中斷時可能會導致 SerialPort 發生異常所以呢 我們必須要把重複的值弄掉
void find_port()
{
string[] ports = SerialPort.GetPortNames();
// Display each port name to the console.
int count = 0;
foreach (string port in ports)
{
count += 1;
}
if (count <= 0)
{
comboBox1.Items.Clear();
comboBox1.Text = "";
this.button2.Text = "Connect";
}
if (count > 0)
{
comboBox1.Text = "";
comboBox1.Items.Clear();
string[] result = ports.Distinct().ToArray();
foreach (string port in result)
{
comboBox1.Items.Add(port);
}
}
}
void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
if (Connection == true)
{
// byte RB = Byte.Parse(serialPort.ReadByte().ToString());
String back = serialPort1.ReadLine();
if (back.IndexOf("test") >= 0)
{
string back2 = back.Replace("test", "");
knobControl2.Value = Convert.ToInt32(back2);
// MessageBox.Show(back2);
}
else if (back.IndexOf("warring") >= 0)
{
string back2 = back.Replace("warring", "");
if (Convert.ToInt32(back2) == 0)
SetText2("0");
else
SetText2("1");
// MessageBox.Show(back2);
}
else
SetText(back);
}
}
catch
{ serialPort1.Close(); }
//byte RB = Byte.Parse(serialPort1.ReadByte().ToString());
//SetText( RB.ToString() + " ");
// listBox1.Items.Add(RB.ToString());
}
Serial 跨執行續更新UI
delegate void SetTextCallback(string text);
private void SetText(string text)
{
if (Connection == true)
if (this.listBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.listBox1.Items.Add(text);
this.listBox1.SelectedIndex = this.listBox1.Items.Count - 1;
}
}
private void SendPhone()
{
char[] textBuf;
textBuf = this.textBox1.Text.ToCharArray();
rs232Output(textBuf);
//轉換成字串
textBuf = "01001043".ToCharArray();
rs232Output(textBuf);
//直接寫入字串
serialPort1.Write("0");
//寫入Byte
/*
byte[] bytestosend = { 0x14, 0x0E };
serialPort1.Write(bytestosend, 0, bytestosend.Length);
/*
}
// 經由RS232 字串傳送
private void rs232Output(char[] phoneNum)
{
try
{
for (int i = 0; i < phoneNum.Length; i++)
{
serialPort1.Write(phoneNum, i, 1);
//serialPort.Write("A");
}
/*
// 傳送 Enter 的 ascii code
byte[] commEnter = new byte[] { 0x0D, 0x0A };
for (int i = 0; i < 2; i++)
{
serialPort1.Write(commEnter, i, 1);
}*/
}
catch
{
this.button2.Text = "Connect";
comboBox1.Text = "";
comboBox1.Items.Clear();
try
{
serialPort1.DiscardInBuffer(); // RX
serialPort1.DiscardOutBuffer(); // TX
// 關閉 PORT
this.serialPort1.Close();
}
catch { }
}
Console.WriteLine("output Phone Number" + phoneNum.ToString());
}
if (rs232key)
{
// 打開 PORT
this.button2.Text = "Close";
// 檢查 PORT 是否關閉
// 設定使用的 PORT
serialPort1.PortName = (string)comboBox1.SelectedItem;
// 初始化 PORT
this.serialPort1.BaudRate = 115200; // baud rate = 9600
this.serialPort1.Parity = Parity.None; // Parity = none
this.serialPort1.StopBits = StopBits.One; // stop bits = one
this.serialPort1.DataBits = 8; // data bits = 8
// 設定 PORT 接收事件
serialPort1.DataReceived += new SerialDataReceivedEventHandler(SerialPort_DataReceived);
// 檢查 PORT 是否關閉
if (!serialPort1.IsOpen)
this.serialPort1.Close();
serialPort1.Open();
// 清空 serial port 的緩存
serialPort1.DiscardInBuffer(); // RX
serialPort1.DiscardOutBuffer(); // TX
serialPort1.Write("2");
rs232key = false;
// comboBox1.Text = "";
// this.button2.Text = "Connect";
// rs232key = true;
// timer2.Enabled = false;
//serialPort1.Close();
Connection = true;
}
else
{
Connection = false;
this.button2.Text = "Connect";
timer2.Stop();
timer2.Enabled = false;
// 清空 serial port 的緩存
//serialPort1.DiscardInBuffer(); // RX
// serialPort1.DiscardOutBuffer(); // TX
// 關閉 PORT
Application.DoEvents();
this.serialPort1.Close();
rs232key = true;
comboBox1.Text = "";
}
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case Win32.WM_DEVICECHANGE: OnDeviceChange(ref m); break;
}
base.WndProc(ref m);
}
void OnDeviceChange(ref Message msg)
{
int wParam = (int)msg.WParam;
if (wParam == Win32.DBT_DEVICEARRIVAL)USB有裝置插入
{
find_port();
label1.Text = "Arrival";
}
else if (wParam == Win32.DBT_DEVICEREMOVECOMPLETE)USB有裝置拔除
{
label1.Text = "Remove";
comboBox1.Items.Clear();
comboBox1.Text = "";
this.button2.Text = "Connect";
try
{
serialPort1.DiscardInBuffer(); // RX
serialPort1.DiscardOutBuffer(); // TX}
}
catch
{ }
serialPort1.Close();
rs232key = true;
}
}
void RegisterHidNotification()
{
Win32.DEV_BROADCAST_DEVICEINTERFACE dbi = new
Win32.DEV_BROADCAST_DEVICEINTERFACE();
int size = Marshal.SizeOf(dbi);
dbi.dbcc_size = size;
dbi.dbcc_devicetype = Win32.DBT_DEVTYP_DEVICEINTERFACE;
dbi.dbcc_reserved = 0;
dbi.dbcc_classguid = Win32.GUID_DEVINTERFACE_HID;
dbi.dbcc_name = 0;
IntPtr buffer = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(dbi, buffer, true);
IntPtr r = Win32.RegisterDeviceNotification(Handle, buffer,
Win32.DEVICE_NOTIFY_WINDOW_HANDLE);
if (r == IntPtr.Zero)
label1.Text = Win32.GetLastError().ToString();
}
}
class Win32
{
public const int
WM_DEVICECHANGE = 0x0219;
public const int
DBT_DEVICEARRIVAL = 0x8000,
DBT_DEVICEREMOVECOMPLETE = 0x8004;
public const int
DEVICE_NOTIFY_WINDOW_HANDLE = 0,
DEVICE_NOTIFY_SERVICE_HANDLE = 1;
public const int
DBT_DEVTYP_DEVICEINTERFACE = 5;
public static Guid
GUID_DEVINTERFACE_HID = new
Guid("4D1E55B2-F16F-11CF-88CB-001111000030");
public static Guid
GUID_DEVINTERFACE_USB_DEVICE = new
Guid("A5DCBF10-6530-11D2-901F-00C04FB951ED");
[StructLayout(LayoutKind.Sequential)]
public class DEV_BROADCAST_DEVICEINTERFACE
{
public int dbcc_size;
public int dbcc_devicetype;
public int dbcc_reserved;
public Guid dbcc_classguid;
public short dbcc_name;
}
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr RegisterDeviceNotification(
IntPtr hRecipient,
IntPtr NotificationFilter,
Int32 Flags);
[DllImport("kernel32.dll")]
public static extern int GetLastError();
}

serial