InvalidSourceModifier Archive
このまえ「Windows Live WriterプラグインからエントリのHTMLDocumentを取得する方法」というエントリでWLW編集画面のHTMLDocumentオブジェクトを取得する方法を紹介したけれども、その方法にはまだ解決できていない問題があり、今回は自分がどこで躓いているのかを説明しつつ嘆くエントリ(笑)。
さて、現在のInvalidSourceModifierは以下のようなソースになっている。
extern alias MicrosoftMshtml;
extern alias WriterInteropMshtml;
using System;
using WindowsLive.Writer.Api;
using System.Windows.Forms;
using MicrosoftMshtml.mshtml;
using WindowsLive.Writer.PostEditor;
using WriterMshtml = WindowsLive.Writer.Mshtml;
namespace InvalidSourceModifier {
//TODO:ImagePathの設定!
[WriterPlugin("9388e56b-c684-4e04-b7f6-b8cc224d70b2", "InvalidSourceModifier", PublisherUrl = "http://www.sharplab.net/")]
public class InvalidSourceModifier : PublishNotificationHook {
public override bool OnPrePublish(System.Windows.Forms.IWin32Window dialogOwner, IProperties properties, IPublishingContext publishingContext, bool publish) {
PostEditorForm postEditorForm = getPostEditorForm(dialogOwner);
WriterMshtml.MshtmlControl mshtmlControl = (WriterMshtml.MshtmlControl)findControlByName(postEditorForm, "MshtmlControl", "WindowsLive.Writer.Mshtml");
IHTMLDocument3 doc = (IHTMLDocument3)mshtmlControl.HTMLDocument;
IHTMLElementCollection allElement = doc.getElementsByTagName("*");
foreach (IHTMLElement elem in allElement) {
object align = elem.getAttribute("align", 0);
object border = elem.getAttribute("border", 0);
if (!(align == null || align is DBNull)) {
elem.removeAttribute("align", 0);
elem.style.styleFloat = (string)align;
}
if (!(border == null || border is DBNull)) {
elem.removeAttribute("border", 0);
elem.style.borderWidth = (string)border;
}
}
updateTextEditorControl(postEditorForm);
return true;
}
private void updateTextEditorControl(PostEditorForm postEditorForm) {
WriterMshtml.MshtmlEditor mshtmlEditor = (WriterMshtml.MshtmlEditor)findControlByName(postEditorForm, "MshtmlEditor", "WindowsLive.Writer.Mshtml");
mshtmlEditor.Focus();
Control test = findControlByName(postEditorForm, "PostEditorMainControl", "WindowsLive.Writer.PostEditor");
}
private PostEditorForm getPostEditorForm(IWin32Window postProgressForm) {
return (PostEditorForm)((Form)Form.FromHandle(postProgressForm.Handle)).Owner;
}
private Control findControlByName(Control control, string controlName, string controlNamespace) {
foreach (Control cChild in control.Controls) {
Type t = cChild.GetType();
if (t.Name == controlName && t.Namespace == controlNamespace) {
return cChild;
}
if (cChild.HasChildren) {
Control returned = findControlByName(cChild, controlName, controlNamespace);
if (returned != null) {
return returned;
}
}
}
return null;
}
}
}
まず、getPostEditorFormメソッドで投稿の進捗状況を表すプログレスバーを載せたFormを基に、親のPostEditorFormを取得、その後、findControlByNameメソッドを使い、PostEditorForm内から、nameとnamespaceを頼りにMshtmlControlコントロールを探し、そのHTMLDocumentプロパティから取得する、というやり方。
これでめでたく「標準」モードや、「Webプレビュー」モードのHTMLDocumentオブジェクトが習得できるのだけれども、HTMLDocumentオブジェクトに対して操作を加えると、「HTMLコード」画面での内容と、HTMLDocumentの不整合が起きてしまう。特に、表示モードを「HTMLコード」としていた場合、HTMLDocumentに対してプラグインから操作後に表示モードを「標準」に戻すと、HTMLDocumentに対する操作内容が飛んでしまう。
む~。なんとかならんものか。誰か知恵をお貸しくださいませ。
自分の間抜けさに笑える。
publish notification hooksを使ったプラグインを作ってみようということで、LiveWriterの出力するソースを投稿時に書き換えるプラグイン(InvalidSourceModifier)をつくることにした。
とか言って実際に作っていたのだけれども、いざ形になってきてコンパイルしてみると、
エラー 1 プロパティまたはインデクサ ‘WindowsLive.Writer.Api.IPostInfo.Contents’ は読み取り専用なので、割り当てることはできません。
というオチ。OnPrePublishメソッドをオーバーライドすれば投稿前にコンテンツの中身を書き換えられるという訳じゃなかったんかい!勘違いでした…。
どーするかなー。後はhookする対象をOnPostPublishメソッドに変更したうえで、投稿後直ぐXML-RPCで直接WordPress上のコンテンツを書きかえる位しかやりようがないかな・・・。つうかそれならWordPressのプラグインをPHPで書いた方が早いか(笑)
publish notification hooksを使ったプラグインを作ってみようということで、LiveWriterの出力するソースを投稿時に書き換えるプラグイン(InvalidSourceModifier)をつくることにした。
using System;
using System.Collections.Generic;
using System.Text;
using WindowsLive.Writer.Api;
namespace InvalidSourceModifier {
//TODO:ImagePathの設定!
[WriterPlugin("9388e56b-c684-4e04-b7f6-b8cc224d70b2", "InvalidSourceModifier", PublisherUrl = "http://www.sharplab.net/")]
public class InvalidSourceModifier : PublishNotificationHook {
public override bool OnPrePublish(System.Windows.Forms.IWin32Window dialogOwner, IProperties properties, IPublishingContext publishingContext, bool publish) {
//publishingContext.PostInfo.Contents
System.Windows.Forms.MessageBox.Show("test");
return true;
}
}
}
…まだこれだけだけど。
さて、実際にコンパイルしてLiveWriterに登録してみると、SDKに付属していたNew SDK Features.docの以下の記述通り、
Unlike content source plugins, publish notification hooks can be enabled or disabled by the user on a per-blog basis. The first time a publish operation occurs for a particular blog since a publish notification hook was installed, the user will be asked if the hook should be enabled or disabled for that blog.
New SDK Features.doc
Blog別にプラグインの有効/無効が管理されているのが確認できた。上手く出来てるなー。ちょっとしたことだけど、これは便利だ。