2013-04-05

Bypass exception for developing purpose "Trust anchor for certification path not found"

Original: http://stackoverflow.com/questions/6825226/trust-anchor-not-found-for-android-ssl-connection

Dùng bypass exception verify SSL (develop only) trong trường hợp gặp lỗi do cert ko match. Gọi trước khi execute HTTP request


/**
 * Trust every server - dont check for any certificate
 */
private static void trustAllHosts() {
       // Create a trust manager that does not validate certificate chains
       TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
              public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                     return new java.security.cert.X509Certificate[] {};
              }

              public void checkClientTrusted(X509Certificate[] chain,
                           String authType) throws CertificateException {
              }

              public void checkServerTrusted(X509Certificate[] chain,
                           String authType) throws CertificateException {
              }
       } };

       // Install the all-trusting trust manager
       try {
              SSLContext sc = SSLContext.getInstance("TLS");
              sc.init(null, trustAllCerts, new java.security.SecureRandom());
              HttpsURLConnection
                           .setDefaultSSLSocketFactory(sc.getSocketFactory());

              HttpsURLConnection
                           .setDefaultHostnameVerifier(new HostnameVerifier() {
                                  @Override
                                  public boolean verify(String hostname,
                                                SSLSession session) {
                                         return true;
                                  }
                           });
       } catch (Exception e) {
              e.printStackTrace();
       }
}

2013-04-02

ActionBar one-line with tabs

Dùng tabs embedded để ép ActionBar hiển thị trên 1 dòng

Bài viết trên stackoverflow
http://stackoverflow.com/questions/12392541/replicate-actionbar-tabs-with-custom-view/12703960#12703960

Trên Google Group
https://groups.google.com/forum/#!topic/actionbarsherlock/hmmB1JqDeCk

Code dùng reflection


// Hide the home title
ActionBar bar = getSupportActionBar();
bar.setDisplayShowTitleEnabled(false);
// bar.setDisplayShowHomeEnabled(false);

// pre-ICS
if (bar instanceof ActionBarImpl) {
       enableEmbeddedTabs(bar);

       // ICS and forward
} else if (bar instanceof ActionBarWrapper) {
       try {
              Field actionBarField = bar.getClass().getDeclaredField(
                           "mActionBar");
              actionBarField.setAccessible(true);
              enableEmbeddedTabs(actionBarField.get(bar));
       } catch (Exception e) {
              LogUtils.e(TAG, "Error enabling embedded tabs", e);
       }
}

2013-01-11

Đi tới tương lai, bước nhảy alpha trong Doraemon ... và đôi điều suy nghĩ về việc training

Buổi tối rảnh rỗi ...

Mình ngồi nghĩ lại 1 chút về việc training. Đây là cũng là một phần công việc của mình. Có một điều mình luôn tự nhủ "đừng có giải thích gì đó cho một người không thể hiểu hoặc không muốn tìm hiểu". Tuy nhiên nhiều lúc mình lại không làm vậy. Nếu không thể làm được thì mọi công việc training hầu như vô nghĩa. Nó cũng giống như chuyện học vật lý cao siêu mà mọi người hay thấy: đi tới tương lai, không gian n-chiều ...

Mình đề cập chuyện này vì gần đây vừa nhậu và có nói chuyện vui với 1 thằng bạn. 2 thằng gặp nhau nhậu khuya nói chuyện phiếm từ kinh tế, chính trị, rồi qua dạy dỗ con cái ... rồi tới vật lý. Cũng là điều lý thú, nó gợi đến chuyện training kể cả cho bản thân và cho người khác, hoặc cho con trẻ sau này.

 Chẳng là lúc còn đi học phổ thông mình cũng có nghe qua những điều "cao siêu" về vật lý như vậy. Nhưng thực sự thì chẳng có bận tâm tìm hiểu nó là gì, cũng coi truyện Doraemon nào là bước nhảy alpha ... lúc đó game PS hấp dẫn hơn. Hẳn nhiều người cũng như thế. Thực sự nếu tìm hiểu cũng không khó tìm được tài liệu có thể đọc hiểu.

Bắt đầu bằng chuyện đầu tiên "đi tới tương lai", một khái niệm mà thực ra mình cũng không quan tâm cách giải thích bản chất cũng như mãi khi vào đại học mới có thể tìm được các giải thích dễ hiểu (nếu tính theo khái niệm thông dụng mà lớp Toán mình học thì không biết giải thích = ngu "cơ bản"). Mình nhận ra mức độ quan tâm của người muốn tìm hiểu, sự truyền tải và nâng cấp từ những điều người đọc đã biết và theo 1 quá trình mới chính là điểm mấu chốt.

Lúc mới vào ĐH mỗi lần về nhà mình thức rất khuya và hình như xem 1 chương trình trên TV hình như 2 hay 3h gì đó. Mà chẳng hiểu sao những chương trình như vậy rất ít khi chiếu buổi sáng. Cơ bản chương trình đó làm cho nó không có gì khó hiểu và mình nghĩ sau này cũng có thể giải thích cho con mình hoặc kiếm cho nó xem những gì tương tự.

Ý tưởng nó như sau: chấp nhận vận tốc ánh sáng là lớn nhất. Không chấp nhận chuyện này thì dừng ở đây. Còn nó có lớn nhất không thì chẳng ai biết, mà cũng chưa ai nói Einstein sai cả, nên mọi người vẫn cứ cho là vậy. Giả sử có một con tàu di chuyển với vận tốc thấp hơn vận tốc ánh sáng 5km/h. Và lúc đó trên tàu có một cô bé chạy với vận tốc lớn hơn 5km/h cùng chiều con tàu.

Như thế thì tính toán vận tốc tương đối với 1 người dưới đất sẽ phải lớn hơn vận tốc ánh sáng. Điều này là không thể được vì vi phạm việc chúng ta đã chấp nhận vận tốc ánh sáng lớn nhất. Như vậy thì đối với người dưới đất con bé "phải có" tốc độ nhỏ hơn 5km/h, tức cô bé trong mắt người dưới tàu (nếu thấy được, toàn bộ đang là lập luận) phải hoạt động chậm hơn (kiểu từ từ như trong film Matrix ...). Điều này có nghĩa là cô bé trên tàu thì hoạt động bình thường, còn đối với người dưới tàu thấy cô bé hoạt động rất chậm hay nói ngược lại thời gian những người ở dưới tàu trôi qua nhanh hơn.

Nếu con tàu này cứ chạy vòng vòng thì khoảng chênh lệch này càng ngày càng đáng kể. Có khi tàu dừng và cô bé xuống tàu thì thế giới đã trải qua mấy chục năm ... àh như vậy được gọi là đến tương lai nhưng mà chỉ đến rồi thôi ... 1 chiều. Có lẽ như vậy thì ít người muốn vì sẽ mất người thân, thành kẻ ngu ngơ trong 1 thế giới xa lạ. Hoặc họ là những người bị bệnh hiểm nghèo ... cần nền y học tiến bộ hơn. Đến đây thì mình nghĩ một đứa bé vẫn có thể hiểu chừng lớp 5 lúc đó mình nhớ đã tính toán cộng vận tốc.

Về chuyện thứ 2 để kết thúc và đi ngủ mình sẽ nói về bước nhảy alpha trong Doraemon với 1 cách giải thích mình coi được trong một chương trình dạy cho thiếu nhi của Pháp sau này mình mới biết là khá thông thường (xin lỗi lâu quá không nhớ chương trình nó tên gì nữa), lẽ dĩ nhiên không giống cách Doraemon giải thích cho Nobita. Đầu tiên phải nhắc đến khái niệm topology.

Để đơn giản thì hình dung với người không chuyên 1 ví dụ thường dùng là vẽ 1 vòng tròn lên 1 miếng cao su. Rồi chúng ta có thể kéo miếng cao su về 4 hướng, cái hình được vẽ sẽ là hình vuông hay hình chữ nhật hoặc đại loại cũng giống vậy. Như vậy hình tròn với hình vuông là 1 trong topo, nó khác nhau là do bạn cảm nhận được ra sao. Topo là một cái cơ sở cần cung cấp và tới đây mình sẽ nói đến sự hệ thống, quá trình và sự nâng cấp trong training.

Bước thứ 2 một ví dụ để chứng minh việc cảm nhận khác nhau và trong bước này liên quan đến khái niệm "hình dạng vũ trụ". Một game hầu như quen thuộc mà đến giờ nếu ai là game developer vẫn tập làm khi vào một platform mới là asteroid, astronoid hay spaceship, space war ... tiếng Việt đều gọi là "bắn phi thuyền".

Lấy ví dụ game 2D, khi con tàu đi lên hết màn hình phía trên nó lại xuất hiện ở dưới, tương tự như vậy khi đi 2 bên, kể cả đi chéo ...Nếu chỉ nhìn màn hình thì "chúng ta" sẽ giống những con người trong phi thuyền chỉ cảm nhận 2D cứ đi thằng hoài rồi lại về chỗ cũ. Họ có thể lái phi thuyền lên xuống qua, lại nhưng không thể bay ra khỏi màn hình video game được. Vậy liên quan gì đến topology và nâng cấp chứ?

Như vậy "vũ trụ" trong trò game này, có những điểm đầu và điểm cuối "vũ trụ" là một. Vậy có gì trong thế giới 3D đáp ứng được những hoạt động đó. Nếu chỉ băng ngang qua màn hình rồi lại xuất hiện phía bên kia ---> nó có vẻ giống đi vòng quanh 1 hình trụ mở rộng là hình cầu chẳng hạn. Chúng ta "những con người to lớn" nhìn thấy được toàn bộ mô hình 3D, còn những "con người nhỏ bé" trong phi thuyển vẫn tưởng rằng đang đi thẳng trên mặt đất bằng phẳng. Vì sao lại liên quan topology? Bởi về mặt căn bản hình cầu có thể đập dẹp xong rồi kéo ra cho giống màn hình PC :D.

Hay một ví dụ khác là minh họa trên Wikipedia tiếng Việt về topology, tách cafe, hay bánh donut là những topo có 1 lỗ thủng.


Dưới con mắt tôpô học, cái cốc và cái vòng là một


Một tách cà phê trở thành vòng xuyến qua sự biến dạng hình học bảo toàn các bất biến tô pô. Cả tách cà phê và bánh vòng đều có những tính chất tô pô hoàn toàn giống nhau.

http://offroadinghome.blogspot.com/2010/08/gps-maps-106-reading-topo-map.html


Vậy đi từ đầu này sang đầu kia trái đất thì đường nào nhất nhất. Hẳn nhiên nếu có đường xuyên trái đất thì đường thẳng xuyên trái đất đó là ngắn nhất. Vấn đề là trái đất không có một lỗ thủng như vậy.
Lỗ thủng :D là một đặc điểm mà topology nhiên cứu.

Trên Wikipedia có nêu:

"Như vậy có thể nói một cách nôm na rằng tô pô là một ngành nghiên cứu về đặc tính của các cấu trúc đặc có tính siêu co giãn, siêu biến dạng nhưng lại không thể bị cắt rời thành nhiều mảnh, không thể bị đâm thủng hay bị dán dính vào nhau."

Tuy nhiên có một cái hình hay hơn từ đó thêm nhiều hình dung, hình mà trong topo học hay ví dụ là hình cái bánh donut. Phi thuyền có thể đi thẳng lên, sang ngang vạch một đường tròn trên cái bánh donut, hoặc di chuyển chéo vạch một elipse.





Dĩ nhiên câu hỏi cũ đạt ra trong trường hợp này nếu đi từ đầu này sang dầu kia cái bánh (mũi tên xanh), đường nào ngắn nhất. Với những "con người nhỏ bé trong phi thuyền", "đi thằng" là ngắn nhất. Nhưng chúng ta biết rằng đường họ đi trên bề mặt cái bánh donut chẳng phải "đường thẳng". Nếu "tiến bộ", họ nên có 1 con tàu, đi xuyên qua khoảng không giữa cái bánh mới phải. Có thể họ gọi đó là bước nhảy alpha.

Cũng như chúng ta, giống trong một thế giới có nhiều hơn 3 chiều. Nhiều nhà khoa học cho rằng chiều còn lại chính là thời gian. Tuy nhiên ta chỉ cảm nhận được 3 chiều. Nó giống như những "người bạn nhỏ" trong phi thuyền 2D, chỉ cảm nhận được 2 chiều trong thế giới 3 chiều. Và thực sự không cách nào cảm nhận được hơn 3 chiều, tất cả chỉ là tưởng tượng. Ai mà biết hình dạng vũ trụ như thế nào.

Đến đây nếu hỏi không có topo học thì chúng ta sẽ nói bằng cái gì trước. Nếu không tìm ra video game, hay quả đất hay hình cái bánh donut, không đi từ 2D sang 3D chúng ta có thể nói 1 thứ mà chẳng biết có tồn tại không hoặc thậm chí có cũng chẳng có bất kỳ ai có thể cảm nhận. Đó là sự mở rộng, là sự quan trọng của công việc cung cấp cơ sở và phải có quá trình nâng cấp. Tất nhiên training những điều cảm nhận được tính ra phải dễ hơn giải thích bước nhảy "tào lao" alpha mà chẳng ai dám chắc có hay không. Good night ...




2013-01-03

Implementing RESTful clients on Android 4.0

Ai đã từng muốn phát triển một RESTful app trên Android hẳn đã xem qua Google I/O 2010
Developing Android REST client applications. Nếu chưa từng làm thì video này sẽ giới thiệu những vấn đề rất quan trọng khi làm app với REST. Tuy nhiên có nhiều thứ đã thay đổi từ lúc đó đến giờ như Fragment, AsyncTaskLoader ... Mình cũng rất lâu rồi không đụng Android từ lúc chưa ra 3.0, cần update thêm haizzzz...

Trên stackoverflow có một article về việc này
Is the rest client app design approach in google io 2010 still up to date?

Về các cách tiếp cận đề cập trong Google I/O 2010 thì không có source code demo. Để có thêm tham khảo thì link rất hữu ích của Neil Goodman với Part 1 và Part 2.

Có thể tham khảo Robospice
https://github.com/stephanenicolas/robospice

2012-12-16

Ngày cuối năm ...


Ngày cuối năm,

Cũng những ngày này cách đây 4 năm mình đã xin nghỉ công ty mà mình đã làm việc 3 năm, vào đúng 1 ngày trước dịp xét tăng lương. Mọi người kêu sao không đợi qua Tết để nhận thưởng; mình cũng biết chứ, chỉ là cảm thấy rằng ko đợi được. 1 tháng lương đó + tiền tăng lương không đáng giá bằng việc hết phải chán nản từ nhà đi đi về về E-town suốt 2,3 tháng. Lúc đó mình đã từng viết rằng sẽ kiếm một cái gì đó vui vẻ để làm và cố gắng kiếm tiền còn những công việc buồn chán thì kệ nó.

Nói thì nói vậy nhưng hình như sau đó mình chỉ theo vế đầu. Không làm việc cho một công ty nào cả. Bạn bè kêu rằng mình  "lười" nhưng nghĩ lại mình đâu có lười, cũng làm từ trưa tới tối khuya, chỉ là lệch thời gian thôi. Thời gian rồi cũng trôi nhanh dù là làm "tạm bợ", hết tiền thì kiếm việc làm có tiền thì từ từ :D, rồi việc này việc khác, cũng vẫn đủ sống...

1 thời gian theo đuổi những không khí gọi là "mới so với trước đây" + thất bại trong việc mở quán game mất 1 số tiền cũng khá nhiều ... mình xác định mình sẽ lại đi làm thuê. Dù gì làm thuê vẫn còn có tiền đều đặn hàng tháng mà cũng nhẹ đầu hơn, đã vậy còn ra đường và ăn cơm trưa đều đặn hơn. Mình search trên 1 vòng, activate lại account trên mấy trang kiếm việc, rồi chuẩn bị CV dù chưa định gửi đi đâu. Quay qua quay lại cũng chỉ thấy E-Town, Quang Trung ... Lại lần nữa không cảm thấy thoải mái rồi từ chối các offer gọi đến.

Sau đó theo lời gọi của sếp và bạn bè cũ, mình về làm lại ở công ty trước đây, bên đó đang làm 1 số sp mới. Lúc đầu về thì cũng nhiều ý tưởng lắm, công ty cũng đã phát triển hơn. Nhưng rút cuộc 1 thời gian thì cũng chỉ làm 1 mình, phát triển mấy cái sản phẩm mà cuối cùng chẳng ai dùng. Việc thay đổi thói quen của người dùng không hề đơn giản. Năm đó đăng ký học chuyển đổi, rồi cưới vợ. Mọi việc cứ dần trôi qua ... và có lẽ đó là hai chuyện có thể coi là thành công trong năm. 1 năm sau công ty cũ "phá sản". Không phải phá sản theo nghĩa hết tiền, căn bản không phải do thiếu tiền mà thiếu hướng đi và thất bại trong định hướng. Những ngày cuối sếp có hỏi nên giữ lại nhiều developer không, mình nghĩ nên thông báo cho họ kiếm việc mới. Rồi sau đó công ty dọn VP sang Q.7, mình lại ở nhà làm, từ từ mất lửa và bỏ hẳn những việc làm dở version cho iOS, Android... Ý tưởng tốt thì sếp có nhưng có lẽ sếp nghĩ sai về IT. Nó không dễ đến nỗi ai cũng có thể làm và càng không phải là muốn làm gì thì làm. Quan trọng mình nghĩ chỉ đầu tư sơ sài trong khi mong muốn có 1 sản phẩm mang lại tiền là điều không thể.

Thời gian đó mình cũng về xem lại việc làm trong công ty đã cùng mở với thằng bạn. Dù gì công ty cũng có 1 chữ tên mình... 6 tháng sau tự nghĩ mình vẫn chưa thể giúp gì cho nó phát triển hơn mà công việc này giúp mình chán nản hơn và "ít tiền hơn" (tất nhiên)... mình lại tạm thời ra đi. Vẫn chưa thấy hướng đi và làm 1 công ty mà vẫn phải kiếm tiền chỗ khác để sống thì cũng ko khoái, cảm thấy không focus được. Lần thứ 2 lại chuẩn bị CV (update lại tình trạng hôn nhân), lại search và lại cảm thấy 1 chút gì đó lưỡng lự. Không phải sợ rằng mình không đáp ứng được công việc nhưng sợ rằng mình không phải là người thuộc 1 tổ chức nào đó. Đã 3 năm hầu không dậy sớm, công việc 1 mình, schedule chỉ có mỗi tên mình, không daily report... Công ty là một từ gì đó xa lạ và mình vẫn chần chờ...

Với tâm trạng đó xui rủi thế nào mình lại gặp 1 công ty làm 1 sp mới. Và bây giờ khoảng 1 năm sau ... lần thứ 3 nghĩ rằng mình sẽ chuẩn bị CV. Lần này là vì tiền, thời gian và quan trọng là cảm thấy không thoải mái. Đầu tiên, tiền là một phần quan trọng kéo nhiều thứ khác đi xuống, tất nhiên không phải là tất cả. Mình nghĩ mình không thể nào tiếp tục làm nếu quá tốn thời gian mà thu nhập lại không ổn định, không có đủ niềm tin. Mình có thể không nhận gì 1 thời gian nhất định. Nhưng cả team thì khác, tới tháng chưa nhận lương thì tinh thần xuống thảm, không thể làm gì trong cái không khí như vậy. Quan trọng hơn là cảm thấy thời gian trôi qua mà không làm được gì. Cảm thấy mất dần niềm tin từ gia đình người thân- những người đã tôn trọng lựa chọn của mình khi mình đã đánh đổi hướng đi này với những hướng đi khác.

Rút cuộc nhìn lại mình nhận thấy mình đang trốn chạy? Trốn chạy công việc đã từng làm là outsourcing, trốn chạy E-Town, Quang Trung, CNC... Nhìn lại mình thích làm cái gì đó khác, bị hấp dẫn bởi nhưng dự án làm sp mới. Mình cũng nhận ra những gì mình gặp thuộc 2 dạng có tiền thì lại không có những thứ khác (nhân sự cùi, kế hoạch, tiếp cận khách hàng) và ngược lại 1 số có thể làm được cái gì đó (chí ít cũng có người cho là vậy) thì lại không có tiền. Tất nhiên sống bằng niềm tin không xấu, chỉ có điều mình không nhận thấy những căn cứ mình có đủ để tin. Tóm lại là chưa đủ tầm và chưa đủ tài, mà ko dám đối mặt. Còn gia đình và nhiều thứ khác cần tiền... 3-4 năm trời không làm được gì, 4-5 tháng không có lương, mượn tiền vợ và bỏ ra cả vài trăm triệu :(. Không làm IT nữa thì bỏ việc và cũng không cần ở tp này nữa???

Cuối cùng năm 2012, nếu không tận thế thì mình vẫn sẽ theo những gì đã viết 4 năm trước nhưng có lẽ sẽ phải hành động khác.

2012-12-11

Windows Shell Extensions


Lâu lắm mới viết lại shell extension ...
Để viết Shell extensions thì có nhiều tutorials ko cần phải nói nữa, search 1 vòng trên CodeProject có thể list ra như series http://www.codeproject.com/Articles/441/The-Complete-Idiot-s-Guide-to-Writing-Shell-Extens hoặc các ví dụ trên CodePlex http://1code.codeplex.com/wikipage?title=WinShell

Hầu hết các ví dụ này dùng ATL, tất nhiên vậy cũng OK. Nhưng có 1 cách tiếp cận hay khá linh động viết COM bình thường không dùng ATL cần note lại là của TortoiseSVN. Đơn giản có thể tóm tắt như sau: ví dụ cần wrap 1 số shell extensions vào 1 chỉ DLL hoặc sử dụng trong trường hợp cần nhiều icon overlays mỗi cho 1 trạng thái của file như syncing, synced, do handler chỉ xử lý bằng IsMemberOf có nghĩa là chỉ xác định có/không hiển thị icon nên phải có 2 CLSID cho 2 trạng thái file.

Giả sử cần 2 icon overlay handlers cho syncing, synced và 1 context menu. Class xử lý icon overlay là IconOverlayExt và class xử lý context menu là ContextMenuExt. IconOverlayExt xử lý hiển thị hay không 2 trạng thái syncing và synced. Ta có các CLSID tương ứng CLSID_Synced, CLSID_Syncing, CLSID_ContextMenu.

Khai báo một enum xác định extension cần tạo:


enum ExtensionState
{
       Invalid,
       IconSynced,
       IconSyncing,
       ContextMenu
};


ShellExtClassFactory chịu trách nhiệm tại ext tùy theo loại ext cần tạo, nhận 1 ExtensionState là member


// This class factory object creates the main handlers -
// its constructor says which OLE class it has to make.
class ShellExtClassFactory : public IClassFactory
{
protected:
    ULONG _refCount;
    // Variable to contain class of object (i.e. syncing, synced, context menu)
    ExtensionState _stateToMake;
      
public:
    ShellExtClassFactory(ExtensionState stateToMake);
    virtual ~ShellExtClassFactory();
      
       // IUnknown members
    STDMETHODIMP         QueryInterface(REFIID, LPVOID FAR *);
    STDMETHODIMP_(ULONG) AddRef();
    STDMETHODIMP_(ULONG) Release();
   
       // IClassFactory members
    STDMETHODIMP           CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *);
    STDMETHODIMP           LockServer(BOOL);
};


Như vậy code DllGetClassObject như sau:


STDAPI DllGetClassObject(const CLSID& rclsid, const IID& riid, void** ppv)
{
       if(ppv == 0)
       {
              return E_POINTER;
       }

       *ppv = NULL;

       // State to get factory
       ExtensionState stateToMake = ExtensionState::Invalid;
       if (IsEqualIID(rclsid, CLSID_Synced))
       {
              stateToMake = ExtensionState::IconSynced;
       }
       else if (IsEqualIID(rclsid, CLSID_Syncing))
       {
              stateToMake = ExtensionState::IconSyncing;
       }
       else if (IsEqualIID(rclsid, CLSID_ContextMenu))
       {
              stateToMake = ExtensionState::ContextMenu;
       }

       if (stateToMake != ExtensionState::Invalid)
       {
              ShellExtClassFactory *classFactory = new (std::nothrow)ShellExtClassFactory(stateToMake);
              if (classFactory == NULL)
              {
                     return E_OUTOFMEMORY;
              }

              // IMPORTANT NOTE: ref count set to 0 at this moment -> do not call Release
              // If your ClassFactory object's reference count initialize with 0, DO NOT call the release method,
              // it seems the COM library would call the release method automatically.
              // Otherwise, you'd get an access exception.
              //
              // If ClassFactory initialize with ref count = 1 -> must call Release
              // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms680760(v=vs.85).aspx
              const HRESULT hr = classFactory->QueryInterface(riid, ppv);
              if (FAILED(hr))
              {
                     delete classFactory;
              }            

              return hr;
       }

       return CLASS_E_CLASSNOTAVAILABLE;
}

NOTE: ở đây cũng lưu ý code COM trong TortoiseSVN khác với code mẫu ClassFactory hay COM hay thấy như trong MSDN chẳng hạn, sau khi QueryInterface sử dụng xong thường gọi Release tuy nhiên reference count TortoiseSVN init là zero trong khi ví dụ thông thường init là 1. Xem thêm http://msdn.microsoft.com/en-us/library/windows/desktop/ms680760(v=vs.85).aspx

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
{
    HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;

    if (IsEqualCLSID(CLSID_FileContextMenuExt, rclsid))
    {
        hr = E_OUTOFMEMORY;

        ClassFactory *pClassFactory = new ClassFactory();
        if (pClassFactory)
        {
            hr = pClassFactory->QueryInterface(riid, ppv);
            pClassFactory->Release();
        }
    }

    return hr;
}



Như vậy là OK đã có ClassFactory và ext cần tạo, trong CreateInstance


STDMETHODIMP ShellExtClassFactory::CreateInstance(LPUNKNOWN unkOuter,
       REFIID riid, LPVOID *out)
{
       if(out == 0)
       {
              return E_POINTER;
       }

       *out = NULL;

       // Shell extensions typically don't support aggregation (inheritance)     
       if (unkOuter)
       {
              return CLASS_E_NOAGGREGATION;
       }

       HRESULT hr;  
       if(_stateToMake == ExtensionState::ContextMenu)
       {
              // The shell will then call QueryInterface with IID_IShellExtInit--this
              // is how shell extensions are initialized.
              ContextMenuExt* contextMenu = new (std::nothrow)ContextMenuExt();  // create the ContextMenuExt object
              if (contextMenu == nullptr)
              {
                     return E_OUTOFMEMORY;
              }

              hr = contextMenu->QueryInterface(riid, out);
              if(FAILED(hr))
              {
                     delete contextMenu;
              }
       }
       else
       {
              // Create the main shell extension object.
              IconOverlayExt* iconOverlay = new (std::nothrow)IconOverlayExt(_stateToMake);  // create the IconOverlayExt object
              if (iconOverlay == nullptr)
              {
                     return E_OUTOFMEMORY;
              }

              hr = iconOverlay->QueryInterface(riid, out);
              if(FAILED(hr))
              {
                     delete iconOverlay;
              }
       }

       return hr;
}

Thêm std::nothrow để kiểm tra kết quả trả về thay vì nhận exception. Tại đây dựa vào ext cần tạo sẽ xử lý.

Còn 1 việc cần giải quyết là IPC giữa shell và app. Có thể dùng RPC, DLL shared segment cũng là 1 khả năng tuy nhiên phải cùng x86 hay 64-bit (app x86 chẳng hạn không thể load shell ext 64-bit), và named pipe có lẽ là hợp lý nhất.

Debug

Về debug chỉ có 1 lưu ý, nếu trong máy có install nhiều app có ext thì nên disable hay tạm thời uninstall. Giả sử máy bạn là developer hay cài TortoiseSVN thì tạm thời bỏ nó đi vì không thể nào debug được, lý do TortoiseSVN sẽ block ngay explorer khi reach break point đâu đó, khi đó chỉ có nước nhấn reset máy (cry).

Để tránh các app khác load ext: 1 số thằng rất hay load như Google Chrome, IDM và Skype trong DLL Attach code 1 đoạn như sau nếu có debugger hay là app test-shell của mình hoặc Explorer hay regsvr32 thì OK:

BOOL APIENTRY DllMain(HMODULE module, DWORD reason, LPVOID reserved)
{
#ifdef _DEBUG
       // If no debugger is present, then don't load the dll.
       // this prevents other apps from loading the dll and locking
       // it.

       bool isInShellTest = false;
       TCHAR fullPath[MAX_PATH + 1];       // MAX_PATH ok, the test really is for debugging anyway.
       DWORD len = GetModuleFileName(NULL, fullPath, MAX_PATH);
       TCHAR fileNameWithoutExt[MAX_PATH + 1];
       TCHAR ext[MAX_PATH + 1];
      
       _tsplitpath_s(fullPath, NULL, 0, NULL, 0, fileNameWithoutExt, MAX_PATH, ext, MAX_PATH);

       TCHAR fileName[MAX_PATH + 1];
       _tmakepath_s(fileName, MAX_PATH, NULL, NULL, fileNameWithoutExt, ext);

       if ((_tcsicmp(fileName, _T("test-shell.exe"))) == 0 || (_tcsicmp(fileName, _T("explorer.exe"))) == 0 ||
              (_tcsicmp(fileName, _T("verclsid.exe"))) == 0 || (_tcsicmp(fileName, _T("regsvr32.exe"))) == 0)
       {
              isInShellTest = true;
       }

       if (!::IsDebuggerPresent() && !isInShellTest)
       {
              return FALSE;
       }
#endif

       switch (reason)
       {
              ...
       }

       return TRUE;
}


Để có thể debug thực hiện:
Thêm Properties -> Build Events -> Post-Build Event:
Command Line: echo "Registering Icon Overlay Library" regsvr32 "$(TargetPath)"

Thêm Debugging
Command: explorer.exe

Để restart Explorer unload ext DLL không tắt bằng Taskbar Manager mà thực hiện
Ctrl + Shift + Right Click vào khoảng trống như hình bên dưới
















2012-10-22

PKCS#12 to GnuPG: Extract and import RSA key

X509 p12 (pfx) file và GnuPG (OpenPGP) không tương thích nhau. Tuy nhiên có thể export RSA key từ p12 file, convert rồi import vào gpg. Theo lý thuyết cả 2 đều thao tác trên public/private cryptography có dùng RSA.


Thực ra nếu xem xét ASCII-armored và PEM chúng ta sẽ thấy khá là giống nhau ngoại trừ BEGIN/END markers thì PGP còn có thêm 1 dòng (line cuối cùng) là checksum. Mình không rõ nhưng theo RFC 4880 là CRC24.

Ví dụ xem xét public key PGP ASCII-armored và RSA PEM

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.11 (GNU/Linux)

mQINBE9NBIQBEADMSzN6b0FaPP0rGiLDWKfH4ehN66Z0SAIynXm6lBHjmO69pNsm
....
5NsttvIOclBY5A==
=Zqph
-----END PGP PUBLIC KEY BLOCK-----




-----BEGIN RSA PUBLIC KEY-----
mQINBE9NBIQBEADMSzN6b0FaPP0rGiLDWKfH4ehN66Z0SAIynXm6lBHjmO69pNsm
...
5NsttvIOclBY5A==
-----END RSA PUBLIC KEY-----

Tại Sysmic.org có chỉ cách convert từ OpenSSL sang GnuPG tuy nhiên là gpgsm (with S/MIME)

Có thể thực hiện như sau:
sudo apt-get install dirmngr
GPG_TTY="tty"
gpgsm --import -v file.p12

Tuy nhiên không thể dùng với gpg. Nếu làm manual thì có lẽ rất vất vả, phải nói là không khả thi. Để import RSA key từ OpenSSL sang GPG mình thực hiện như sau:

Extract private key with passphrase
openssl pkcs12 -in file.p12 -nocerts -out private.pem

Remove passphrase
openssl rsa -in private.pem -out rsa-private.key

Dùng pem2openpgp để convert sang OpenPGP với một string là $USERID (lưu ý install monkeysphere trước để có pem2openpgp)

PEM2OPENPGP_USAGE_FLAGS=authenticate,certify,sign pem2openpgp "Some desc for User ID <any@gmail.com>" < rsa-private.key | gpg --import

Lưu ý: biến môi trường PEM2OPENPGP_USAGE_FLAGS xác định usage là SCA, mặc định pem2openpgp sẽ convert với usage là certify.

gpg: key AC37D3E3: secret key imported

gpg: key AC37D3E3: public key "Some desc for User ID <any@gmail.com>" imported


gpg: Total number processed: 1

gpg:               imported: 1  (RSA: 1)
gpg:       secret keys read: 1
gpg:   secret keys imported: 1

$ gpg --list-secret-keys
/home/xxxx/.gnupg/secring.gpg
------------------------------
sec   2048R/AC37D3E3 2012-10-22
uid                 

Some desc for User ID

<
any@gmail.com

>

Sau khi import xong nhớ thực hiện --edit-key với ID eg 
AC37D3E3 thực hiện enable và trust