在**之前,筆者先分享一些基本知識,首先是12星座。
其次是星和行星
上面的太陽(sun)和月亮(moon)就不必解釋了,其他的行星都給出了英文名、符號和解釋。網路的圖沒有冥王星英文是(pluto)。
好了開始**部分,首先我們要新增用於c#訪問的函式,
#define api_export __declspec(dllexport)
先這裡做個預定義,後面每個函式都要用到。使用功能之前要先給astrolog程式來做個初始化
extern_c api_export void __stdcall init()
初始化好了就可以呼叫實質的函式來生成星圖,儲存星圖到資料夾,並把右側資料資訊儲存到字串來返回
extern_c api_export wchar_t* __stdcall processastrolog(wchar_t* filepath, int year, int month,int day,double time)
;char *v0 = "astrolog";
char *v1 = "-xo";
char *v2 = w2c(filepath);
if (v2 == null) return null;
char * vs = ;
i= fprocessswitches(3, vs);
action();
sprintf(result, "%s", allinfo);
free(v2);
v2 = null;
free(allinfo);
allinfo = null;
return c2w( result);
}extern_c api_export int __stdcall freesmem(wchar_t* intptr)
這裡面還涉及到c#的char是用2個位元組來儲存的而在c++裡面char是用1個位元組來儲存的,從這裡大家也可以理解為什麼筆者放棄在c++裡面直接漢化輸出了。既然有這麼個gap,我們就需要做轉換工作,c#裡面的char對應著c++裡面的wchar_t,傳進來之後要把高位的扔掉,生成乙個長度相等,每位是c++的char大小的空間來存放新字串,反之從c++的字串傳到c#的也要做一次這樣的反操作。大家可以不理解,直接拷貝下面的**用就是了。上面的freesmem函式是因為返回的字串內容要在c#裡面用完了才能銷毀,所以有這個函式供c#來呼叫並銷毀。
wchar_t* c2w(char* cstr)
char* w2c(wchar_t* wstr)
上面的c2w和w2c裡面的c和w分別代表c++的char和wchar_t。
好了可以介紹上面這個processastrolog()函式了,首先給allinfo 分配了一段記憶體來儲存右側資料資訊用來返回到c#,然後更新使用者資料報括年月日時間等的資訊,即更新cicore變數,接著模擬執行一條儲存星圖的命令,這個其實大家可以使用cmd嘗試執行astrolog.exe -xo d:\abc.bmp這樣的語句,就知道本函式的方法了。傳進去後儲存並不是立刻執行的,所以需要加入action()這一句來儲存,最後釋放指標並返回字串結果。
然後就到c#**了,見下面
[dllimport(@"astrolog.dll")]
extern unsafe static void init();
[dllimport(@"astrolog.dll")]
extern unsafe static intptr processastrolog(char* filepath, int year, int month, int day, double time);
先定義dllimport,這個不難。
void processastrolog()
this.richtextbox1.text += marshal.ptrtostringauto(abc);
freeresult= freesmem(abc);}}
if (file.exists(filepath))
messagebox.show(freeresult.tostring());
}catch
}然後要先建1個鏈結字串,固化到記憶體並把記憶體首位址傳進dll,如果用過c#做影象處理的應該對鎖記憶體很熟悉吧。然後把位址,年月日時間等傳進dll,獲取返回的字串連線,並輸出到文字框,因為這個字串所在的記憶體是c++裡面動態開闢的,所以需要釋放,最後載入就可以了。
c++修改專案屬性為輸出dll而不是exe,修改c#的項
目屬性,將目標平台設定為x86,並且允許非安全**。
一切都很不錯,成功執行,成功儲存並返回字串結果。可惜的是,執行不了多久就會記憶體報錯,這真的是百思不得其解的鬱悶事,筆者怎麼說寫**15年了也是混過c和c++的,包括微控制器的彙編,記憶體管理大家都知道是個頭疼事不過筆者還是挺自信的,仔細檢查一下,所有的malloc之後都free了,並設定指標指向null了,c#裡面也把**都放進try catch裡面了,還是報錯,而且記憶體錯誤是致命的不可能繼續執行。
萬般無奈之下,筆者開始了另一種方式,在c#裡面開闢記憶體位址存放返回的字串傳給c++,而c++裡面的只要有malloc那麼在返回到c#之前就free掉,並且做了工作狀態的限制,新建1個布林型別的全域性變數叫dllprocessing,在程式開始的時候才賦值為真程式末尾賦值為假,在為真的狀態下allinfo才能夠被操作,即if(dllprocessing) strcat(allinfo, sz);。並且讓c#的unsafe裡面的**盡量少,最後**如下
dllprocessing = true;
allinfo = resultstring;
/* month, day, year, time in hours, daylight offset, time zone, longitude, latitude, name for chart, name of location */
cicore = ;
char *v0 = "astrolog";
char *v1 = "-xo";
char *v2 = w2c(filepath);
if (v2 == null) return null;
char * vs = ;
fprocessswitches(3, vs);
action();
dllprocessing = false;
free(v2);
v2 = null;
return allinfo;
c#**如下
byte bpara = new byte[2000]; //新建位元組陣列
intptr pret;
unsafe
}if (pret == null)
string strget = system.text.encoding.default.getstring(bpara, 0, bpara.length); //將位元組陣列轉換為字串
string strret = marshal.ptrtostringansi(pret);
this.richtextbox1.text += strret;
這次就好了,沒有深究前面**記憶體出錯的原因,估計是在c++ malloc的字串指標在返回到c#之後沒有立即銷毀,而這段時間c++裡面的函式在看不見的地方有沒有呼叫過不知道,畢竟c++的**並沒有深入去研究,那麼在c#去釋放這段位址的時候可能它已經改變了,就出錯了。所以建議是,自己在c++額外植入的**,用了malloc在自己可預見的範圍內就要銷毀,否則c++原有部分就是個黑匣子,你都不知道會發生什麼。
可以獲得所有需要的資料了,這裡輸出的資料經過筆者篩選,沒用的不輸出,然後可以根據這些資料來做自己想做的事情了。最後要給大家介紹另一位大師的文章也是研究astrolog的,和**沒關係,不過可以獲得不少星盤研究的知識,
計算星座演算法解析
本程式對星座的計算是以公曆為準,計算的方式多種多樣,下面介紹一種計算星座的方法 以通過判斷和計算得到陣列對應的索引來找到星座 import define num n nsnumber numberwithint n 乙個巨集,用來封裝整型數為nsnumber型別的物件,方便存入nsarray的陣列中...
計算演算法複雜度
演算法的複雜度分為時間複雜度和空間複雜度 1.時間複雜度 在計算演算法複雜度時一般只用到大o符號,landau符號體系中的小o符號 符號等等比較不常用。這裡的o,最初是用大寫希臘字母,但現在都用大寫英語字母o 小o符號也是用小寫英語字母o,符號則維持大寫希臘字母 常見的演算法時間複雜度由小到大依次為...
分頁頁碼計算演算法
最近做 用到了分頁頁碼計算的演算法,覺得之前一直用的不好,自己寫了乙個,拿出來與大家共享一下 view code 1 package cnblogs.xiaoqiu.test 23 4 1.如果是5個可見頁碼,1 12345,2 12345,3 12345,4 23456,5 34567,6 456...