2009年8月25日火曜日

Excelにてオートシェイプの文字列を操作する

Excelのオートシェイプの文字列置換検索が出来ないのが非常に不便だったので、
Delphiで操作するのを試してみました。

OLEを操作する場合には、VBAなどが普通なんでしょうけど、Delphiの方が得意なんで
Delphiでやってみます。

OleObjectを使っています。

下記のような感じでやれば操作できました。

宣言
var E_Excel: Variant;
E_Application: Variant;
E_WorkBook: Variant;
E_WorkSheet: Variant;
E_Shape: Variant;

基本的な操作方法
E_Excel := CreateOleObject('Excel.Application');
E_Application := E_Excel.Application;
E_Excel.Visible:=True;
E_Application.WorkBooks.Open(FileName); // XLS ファイルを開く
E_WorkBook := E_Application.ActiveWorkbook;
E_WorkSheet := E_Application.ActiveSheet;
for i:=1 to E_WorkSheet.Shapes.Count do
begin
E_Shape:=E_WorkSheet.Shapes.item(i);
   E_Shape.TextFrame.Characters.Text;
E_Shape.TextFrame.Characters.Text:= 'test';
  end

いちばん苦労したのは、変更したオートシェイプを画面上にスクロール表示させる部分。
これに悩んだのですが、下記のページをいろいろと細かく見ていくと

Shape インターフェイス (Microsoft.Office.Interop.Excel)

BottomRightCell というプロパティがあったんで、

E_Shape.bottomRightCell.Select;

という感じで書いてあげると意図通りに動作してくれた。

ここら辺を使って、エクセルのオートシェイプの文字を検索するツールを作ってみました。
http://mitools.blogspot.com/2009/08/excel.html

2009年8月24日月曜日

削除機能の追加

GoogleAppEngineを久々にいじってみた。
今回は、地図から検索のアプリケーションにようやく削除機能を追加した。

削除機能は、自分が登録したデータに関しては、削除、他人が登録したデータに関しては、
削除リクエストの送信と言うような仕様にしております。

今回苦戦したのは、getObjectByIdを利用してデータを取得する部分。

ローカルのサーバでやるとうまく動作するのだけど、AppEngine上では、
どうしてもうまくいかない。

getObjectByIdでnullが返ってきてしまうようである。


08-23 06:20PM 52.000 /loarsh/greet 500 34ms 30cpu_ms 12api_cpu_ms 0kb Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729),gzip(gfe)
See details
125.52.110.203 - takes90 [23/Aug/2009:18:20:52 -0700] "POST /loarsh/greet HTTP/1.1" 500 113 "http://loarsh.appspot.com/loarsh/333D62B7647DD593777255D4248D6999.cache.html" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729),gzip(gfe)" "loarsh.appspot.com"W 08-23 06:20PM 52.006
com.appspot.loarsh.server.GreetingServiceImpl deleteData: key2
E 08-23 06:20PM 52.029
javax.servlet.ServletContext log: Exception while dispatching incoming RPC call
com.google.gwt.user.server.rpc.UnexpectedException: Service method 'public abstract java.lang.Integer com.appspot.loarsh.client.GreetingService.deleteData(long)' threw an unexpected exception: java.lang.NullPointerException
at com.google.gwt.user.server.rpc.RPC.encodeResponseForFailure(RPC.java:360)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:546)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:166)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.doPost(RemoteServiceServlet.java:86)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:713)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:35)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:237)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
at com.google.apphosting.runtime.jetty.RpcRequestParser.parseAvailable(RpcRequestParser.java:76)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:139)
at com.google.apphosting.runtime.JavaRuntime.handleRequest(JavaRuntime.java:235)
at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4823)
at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4821)
at com.google.net.rpc.impl.BlockingApplicationHandler.handleRequest(BlockingApplicationHandler.java:24)
at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:359)
at com.google.net.rpc.impl.Server$2.run(Server.java:820)
at com.google.tracing.LocalTraceSpanRunnable.run(LocalTraceSpanRunnable.java:56)
at com.google.tracing.LocalTraceSpanBuilder.internalContinueSpan(LocalTraceSpanBuilder.java:516)
at com.google.net.rpc.impl.Server.startRpc(Server.java:775)
at com.google.net.rpc.impl.Server.processRequest(Server.java:348)
at com.google.net.rpc.impl.ServerConnection.messageReceived(ServerConnection.java:436)
at com.google.net.rpc.impl.RpcConnection.parseMessages(RpcConnection.java:319)
at com.google.net.rpc.impl.RpcConnection.dataReceived(RpcConnection.java:290)
at com.google.net.async.Connection.handleReadEvent(Connection.java:428)
at com.google.net.async.EventDispatcher.processNetworkEvents(EventDispatcher.java:762)
at com.google.net.async.EventDispatcher.internalLoop(EventDispatcher.java:207)
at com.google.net.async.EventDispatcher.loop(EventDispatcher.java:101)
at com.google.net.rpc.RpcService.runUntilServerShutdown(RpcService.java:251)
at com.google.apphosting.runtime.JavaRuntime$RpcRunnable.run(JavaRuntime.java:374)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
at com.appspot.loarsh.server.GreetingServiceImpl.deleteData(GreetingServiceImpl.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.apphosting.runtime.security.shared.intercept.java.lang.reflect.Method_$3.run(Method_.java:149)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.apphosting.runtime.security.shared.intercept.java.lang.reflect.Method_.privilegedInvoke(Method_.java:147)
at com.google.apphosting.runtime.security.shared.intercept.java.lang.reflect.Method_.invoke(Method_.java:120)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:527)
... 43 more



下記のようにKeyの定義がLongだとうまくいかないので、
Keyに変えてやってみる。

// @PrimaryKey
// @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
// private Long id;

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;

その際に、一緒にKey→longの変換

key.getId()

long →からKeyへの変換

Key k = KeyFactory.createKey(MapData.class.getSimpleName(), key);

を行ってやってみてもうまくいかない。

しかし、いろいろ動作させているうちに本日登録したデータに関しては、
うまく動作することがわかった。

もしかすると、昔登録したデータに関しては、正しく動作しないのだろうか。

内部的になんか変わったりしているのかもしれないということで
納得することにする。

ちなみに今回追加したAppEngine側のコードはこんな感じです。
登録ユーザと、現在のユーザを比較して、処理を切り分けております。

public Integer deleteData(long key){
Integer ret =null;
PersistenceManager pm = PMF.get().getPersistenceManager();
try{
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
Key k = KeyFactory.createKey(MapData.class.getSimpleName(), key);
MapData md = pm.getObjectById(MapData.class,k);
if (md.getAuthor().equals(user)){
pm.deletePersistent(md);
ret = new Integer(0);
}else{
md.addDownVote();
ret = new Integer(1);
}
}finally{
pm.close();
}
return ret;
}


2009年8月22日土曜日

送るのフォルダの場所をDelphiで取得する方法

Windowsの特殊フォルダの情報を取得する方法。
これを取得するためには、

下記のような感じで書けば言いようです。


if SHGetSpecialFolderLocation(0, CSIDL_SENDTO, pidl) = NOERROR then
begin
try
if SHGetPathFromIDList(pidl, PPath) then
Result := PPath;
finally
CoTaskMemFree(pidl);
end;
end;



参考にしたサイトはこちら。
http://www.delphidabbler.com/articles?article=12

SHGetSpecialFolderLocationを利用すれば、Windowsのほかのいろいろな
特殊フォルダの場所を取得できるようです。

こちらを利用して、私も簡単なプログラムを作ってみました。
それが、こちらです。
http://mitools.blogspot.com/2009/08/blog-post.html

2009年8月12日水曜日

DelphiとJavaの連携

Delphiで作ったプログラムをJavaから呼び出す方法で一番いい方法は
何かなと探していたところ、下記のサイトが一番言い感じだった。

http://www.pacifier.com/~mmead/jni/delphi/

このページには、DelphiからJavaのプログラムを呼ぶサンプルと
JavaからDelphiを呼ぶサンプルの2つがある。

JavaからDelphiを呼び出すほうは、JavaクラスからDelphiのプロジェクトファイルを
生成するプログラムがあり、これが便利。
(通常のJNIにおける、Javahコマンドに該当する部分です。)

これを使えば、数秒でスケルトンは作れてしまう。そのツールは、こちら、。
また、DelphiからJavaを呼び出すサンプルはこちら、

Download

このファイルを回答して、javaファイルをコンパイルして、classファイルを作ってから
Delphiを実行すると動作します。

java側にHttpのやり取りのロジックが書かれていて、それをJava、Delphi間で
やり取りしているサンプルです。