当ブログで「主にC++builderのTipsを扱う」と標榜しておいて、最近はあらぬ方向ばかりに行っておりましたが、今日は久しぶりにC++Builderの記事。
ええ、買いましたよ。ついに、C++Builder XE4。個人で買うにはバージョンアップが「ギリ」の値段なのです。
もうお値段が、趣味ってレベルじゃねーぞ!的な。
僕が所有しているのは、2010。このバージョンが、優待で買う最後のチャンス。
妻に泣きながら土下座してポチリました。娘も泣いてました。すみません。
で、さっそくMacOSXでアプリを動かしたいわけですよ。でも、いろいろやるにはMacのAPIをいじらないといけないわけですよ。
そしてこれがまた、面倒くさい。それでいて、情報がとても少ない。
この世界中で、C++Builder XE4を使って、MacOSXのアプリケーションをつくっているのは、
僕だけなのではないか? そんなありもしない孤独感に苛まされます(本当だったりして)。
さらにハマり続けていると、どこからか『ユー、もうObjective な、C で書いちゃいな YO!』と、もう一人のファンキーな自分が、
甘いリリックを囁いてくるわけですよ。
しかも、どうにかネットでヒントを見つけたとしても、Delphiのコードが多くて、いまからデルファイをbeginしちゃうか‥‥
なんて譫妄症状まで出てくる始末。
でも、とりあえず手元には、C++Builder XE4しかないので、がんばってみる。
逃げちゃダメ。逃げちゃダメだ。とりあえず二本の槍を抜けば、すべてをやり直せる。
手始めに、MacOSXのシステムボリュームの空き容量を取得しようとしたのですが、それがわからない。そこでまた途方に暮れる。
で、ググってみると、やっと出てくるのが、Stack Overflow のQA。
http://stackoverflow.com/questions/16384351/xe4-getting-the-total-disk-size
[pascal]
uses
iOSapi.Foundation, Macapi.ObjectiveC;
function GetTotalDiskSize(FolderName: string): Int64;
var
Dict: NSDictionary;
P: Pointer;
const
FoundationFwk: string = ‘/System/Library/Frameworks/Foundation.framework/Foundation’;
begin
Result := 0;
Dict := TNSFileManager.Wrap(TNSFileManager.OCClass.defaultManager).attributesOfFileSystemForPath(NSStr(FolderName), nil);
if Dict = nil then
Exit;
P := Dict.objectForKey((CocoaNSStringConst(FoundationFwk, ‘NSFileSystemSize’) as ILocalObject).GetObjectID);
if Assigned(P) then
Result := TNSNumber.Wrap(P).unsignedLongLongValue;
end;
[/pascal]
・・・DelphiからiOSの空き容量を取得するコードかよぉ・・・またここで心が折れそうになる。
とはいえ、どうやら、TNSFileManagerクラスを駆使すればなんとかできそうだぞ、と踏みました。
さて、ここからが本題です。
TNSFileManagerというヒントを掴んだら、今度は、C++Builder XE4においてどうやってインプリメントされているかを調べます。
基本的には、以下のように、インストールされたディレクトリに、各々のヘッダファイルが収められているはず。
C:¥Program Files (x86)¥Embarcadero¥RAD Studio¥11.0¥include¥osx¥rtl
ようするに、基本は、MacのAPIでできることをググって、そのキーワードを元に、このディレクトリをGrep検索し、
C++Builder XE4上ではどのようなインターフェースでインプリメントされているのか?を知る、というのが流れでしょうか。
そして、できたのが以下のコード。
まず、ヘッダファイルに、Macapi.Foundation.hppをインクルードします。
[cpp]
#include <Macapi.Foundation.hpp>
[/cpp]
そして、NSFileManagerClassの、defaultManagerをWrapするようにして、システムボリュームのパスを指定します。
ここは前述の、iOSのサンプルコードと一緒です。
[cpp]
void __fastcall TForm1::Button1Click(TObject *Sender)
{
void *error = NULL;
NSFileManagerClass *FileMgr;
NSDictionary *dict =
TNSFileManager::Wrap(FileMgr->defaultManager())->attributesOfFileSystemForPath(NSSTR("/"), &error);
//×NSFileSystemFreeSize
//○NSFileSystemSize
__int64 FreeSpace = (__int64)dict->objectForKey(NSSTR("NSFileSystemSize"));
Label1->Text = IntToStr(FreeSpace);
}
[/cpp]
ここで注意したいのは、iOSではNSFileSystemFreeSizeは取れるのに、C++Builder XE4では取れません(エラーになります)。
理由? なぜなら、C++Builder XE4の方で定義されていないから(笑)。Grepで調べたかぎりではその定義を見つけられませんでした。
だから、ここでは、NSFileSystemSize の方を指定します。
この辺の事情に詳しい方は教えていただけると助かります!
あと、これも見落としがちですが、デバッグするためにMac上で、RAD PAServer XE4.appを起動すると思います。
しかし、Xcode、MacOSXのSDKをインストールした上で、さらにC++Builder XE4上で「SDKの編集」をきちんと行っておく必要があります。
SDKのバージョンがターゲットプラットフォーム(この例では、MacOSX 10.8.3)を選択しているかを確認します。
それで、ようやくMac上での動作を確認しました。
そうですね。まあ、素直にObjective-Cで書いた方が良いかもね(笑)。
このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。
日々の開発作業で気づいたこと共有を。同じところで躓いている人が、 検索で辿り着けたら良いな、というスタンスで記事を書くので不定期更新になります。
コメントする