「スクリプト」の編集履歴(バックアップ)一覧に戻る

スクリプト - (2008/01/31 (木) 21:00:51) のソース

#contents()
*スクリプトによる機能拡張

**検索・マイリスト・ランキングをTubePlayerっぽく一覧表示しつつ画像の一覧表示もする
ソースファイルをメモ帳などに貼り付け、拡張子(.hta)でNicoPlayerのインストールフォルダに保存し実行してください(同じ場所にprototype.jsも置いてください)。もし他の場所に起きたい場合はpathOfDownloadとpathOfNicoPlayerをそれぞれの環境に合わせて編集してください(セパレータはスラッシュ/もしくはダブルバックスラッシュ\\です)。タイトルや再生数などのパラメタを表形式・及び画像で一覧表示します。フィードバックを強化しました。青字はダウンロード済みでクリックすると再生、赤字はまだでクリックすると該当行を強調してダウンロードを開始します。この強調は再表示で解除されます。TitleやPなどヘッダをクリックすると該当項目でソートします(基本降順以後トグル)。
 <hta:application maximizebutton="no" selection="yes"
                  navigable="no" scroll="no" singleinstance="yes"/>
 <html>
  <head>
   <meta http-equiv="MSThemeCompatible" content="yes">
   <style>
    #display  { border:3px double red; color:red; text-align:center; }
    #target   { width:100%; height:90%; overflow-y:scroll; }
    body      { background-color:#f7f7f7; }
    div       { border:solid 1px #ccc; }
    table     { font-size:9pt; width:100%; }
    th        { background-color:black; color:white; cursor:pointer; }
    img       { width:98%; margin:3px; cursor:pointer; }
    .even     { background-color:#f7f7f7; cursor:pointer; }
    .odd      { background-color:#ffffff; cursor:pointer; }
    .omo      { background-color:#e0ffe0; }
    .download { color:red; } .play { color:blue; }
    .now      { background-color:#ffb7b7; }
    .playing  { background-color:#b7b7ff; }
    .activet  { background-color:#ccc; }
   </style>
   <script type="text/javascript" src="prototype.js"></script>
   <script type="text/javascript">
    var pathOfDownload = "";	// ダウンロードパス(任意)
    var pathOfNicoPlayer = "";	// NicoPlayerインストールパス(任意)
    var width = 800, height = 800;
    var lastSortKey = "";
    
    list = { show:[], movies:{}, download:{}, downloaded:{} };
    
    var $_ = function( target, key ) {
     return $A( target.getElementsByTagName( key ) );
    }
    
    window.onload = function() {
     resizeTo( width, height );
     
     var display = document.getElementById( "display" );
     try { Prototype } catch( e ) {
      display.innerHTML = "prototype.jsが見つかりません。<a href='http://www.prototypejs.org/'>"
                        + "こちら</a>よりダウンロードして同じフォルダにおいてください。";
      return;
     }
     
     if( !pathOfNicoPlayer ) {
      unescape( window.location ).match( /file:\/\/\/(.+)\// );
      pathOfNicoPlayer = RegExp.$1;
     }
     
     if( !ini.load( pathOfNicoPlayer + "/nicoplayer.ini" ) ) {
      display.innerHTML = "NicoPlayerが見つかりません。同じフォルダにおいてください。";
      return;
     }
     
     if( !pathOfDownload ) {
      pathOfDownload = ini.download.SavePath;
     }
     
     Element.hide( "display" );
    }
    
    ini = {
     init : function() {
      for( var key in ini ) {
       if( !key.match( /^(init|load)$/ ) ) {
        delete ini[key];
       }
      }
     },
     
     load : function( path ) {
      this.init();
      try {
       var file = ( new ActiveXObject( "Scripting.FileSystemObject" )
                  ).OpenTextFile( path );
      } catch ( e ) {
       return;
      }
      
      var buffer, section;
      while( !file.AtEndOfLine ) {
       var line = file.ReadLine();
       // セクション取得
       if( line.match( /^\[(.+)\]$/ ) ) {
        var newSection = RegExp.$1;
        if( section && !section.match( /^(init|load)$/ ) ) {
         this[section] = buffer;
        }
        buffer = {};
        section = newSection;
       }
       // 設定値取得
       if( buffer && line.match( /^([^=]+)=(.*)$/ ) ) {
        buffer[RegExp.$1] = RegExp.$2;
       }
      }
      file.Close();
      return this;
     }
    }
    
    EscapeUTF8=function(str){
     return str.replace(/[^*+.-9A-Z_a-z-]/g,function(s){
      var c=s.charCodeAt(0);
      return (c<16?"%0"+c.toString(16):c<128?"%"+c.toString(16)
      :c<2048?"%"+(c>>6|192).toString(16)+"%"+(c&63|128).toString(16)
      :"%"+(c>>12|224).toString(16)+"%"+(c>>6&63|128).toString(16)+"%"
      +(c&63|128).toString(16)).toUpperCase()
     })
    };
    
    search = function() {
     list.show.clear();
     lastSortKey = "";
     this.index = 0;
     this.timer = setInterval( "search.exec();", 1000 );
     this.request = function() {
      if( 3 <= ++this.index ){ clearInterval( this.timer ); search.instance = null; }
      var key = EscapeUTF8( $F( "keyword" ) );
      var option = $( "sort" ).value + "&page=" + this.index;
      var url = "http://www.nicovideo.jp/search/" + key + "?" + option;
      new Ajax.Request( url, { method:"get", onSuccess:function( response ) {
       var buffer = document.createElement( "div" );
       buffer.innerHTML = response.responseText;
       var pageGuides   = { root:{ tag:"table", index:7 }, blocks:{ tag:"td" } };
       var blocksGuides = [ ["time", "strong", 0], ["play", "strong", 1], ["src", "img", 1, "src"]
                          , ["comment", "strong", 2], ["mylist", "strong", 3]
                          , ["title", "a", 1], ["name", "a", 1, "href", "((sm|ax)\[0-9]+)"]
                          ];
       var blocks = parsePage( buffer, pageGuides );
       var items = parseBlocks( blocks, blocksGuides );
       list.show = list.show.concat( $H( items ).values() );
       refreshTable();
      } } );
     }
     this.request();
    }
    search.instance;
    search.exec = function() {
     if( !this.instance ) {
      this.instance = new this();
     } else {
      this.instance.request();
     }
    }
    
    ranking = function() {
     list.show.clear();
     lastSortKey = "";
     var option = [$F( "rsort" ), $F( "rspan" ), $F( "rgenre" )];
     var url = "http://www.nicovideo.jp/ranking/" + option.join( "/" );
     new Ajax.Request( url, { method:"get", onSuccess:function( response ) {
      var buffer = document.createElement( "div" );
      buffer.innerHTML = response.responseText;
      var pageGuides   = { root:{ tag:"table", index:7 }, blocks:{ tag:"tr" } };
      var blocksGuides = [ ["time", "strong", 0], ["date", "strong", 1], ["play", "strong", 2]
                         , ["comment", "strong", 3], ["target", "p", 1, "([0-9,]+)" ], ["src", "img", 1, "src"]
                         , ["title", "a", 1], ["name", "a", 1, "href", "((sm|ax)\[0-9]+)"]
                         ];
      var blocks = parsePage( buffer, pageGuides );
      blocks = blocks.findAll( function( block, index ) { return ( index % 2 ) == 0; } );
      var items = parseBlocks( blocks, blocksGuides );
      list.show = list.show.concat( $H( items ).values() );
      refreshTable();
     } } );
    }
    
    mylist = function() {
     list.show.clear();
     lastSortKey = "";
     var url = "http://www.nicovideo.jp/mylist/" + $F( "mylistkeyword" );
     new Ajax.Request( url, { method:"get", onSuccess:function( response ) {
      var buffer = document.createElement( "div" );
      buffer.innerHTML = response.responseText;
      var pageGuides   = { root:{ tag:"table", index:6 }, blocks:{ tag:"tr" } };
      var blocksGuides = [ ["date", "strong", 0], ["time", "strong", 1]
                         , ["play", "strong", 2], ["comment", "strong", 3], ["src", "img", 1, "src"]
                         , ["title", "a", 1], ["name", "a", 1, "href", "((sm|ax)\[0-9]+)"]
                         ];
      var blocks = parsePage( buffer, pageGuides );
      var items = parseBlocks( blocks, blocksGuides );
      list.show = list.show.concat( $H( items ).values() );
      refreshTable();
     } } );
    }
    
    parsePage = function( buffer, guides ) {
     with( guides ) {
      return $_( $_( buffer, root.tag )[root.index], blocks.tag )
     }
    }
    
    parseBlocks = function( blocks, guides ) {
     var items = {};
     blocks.each( function( block ) {
      var buffer = {};
      guides.each( function( g ) {
       with( { key:g[0], tag:g[1], index:g[2], param:g[3], regex:g[4] } ) {
        var value = $_( block, tag )[index][param ? param : "innerHTML"];
        if( regex ) {
         new RegExp( regex, "" ).exec( value );
         value = RegExp.$1;
        }
        buffer[key] = value;
       }
      } );
      items[buffer.name] = buffer;
     } );
     return items;
    }
    
    lastMode = "string";
    var refreshTable = function( mode ) {
     searchFlvFiles();
     switch( mode ) {
     case "string" :
      $( "rstring" ).className = "activet";
      $( "rimage" ).className = "";
      refreshStringTable();
      lastMode = mode;
      break;
     case "image" :
      $( "rstring" ).className = "";
      $( "rimage" ).className = "activet";
      refreshImageTable();
      lastMode = mode;
      break;
     default       : refreshTable( lastMode ); break;
     }
    }
    
    var header = [ ["■", "index", "asc"], ["Title", "title", "desc"], ["P", "play", "asc"]
                 , ["C", "comment", "asc"], ["M", "mylist", "asc"]
                 , ["Time", "time", "asc"], ["ID", "name", "desc"] ];
    
    refreshStringTable = function() {
     var ths = "";
     header.each( function( item, index ) {
      ths += ( new Template( "<th onclick='sort(\"#{key}\", \"#{order}\")'"
             + " onmouseover='this.style.cssText=\"background-color:white; color:black\"'"
             + " onmouseout='this.style.cssText=\"\"'>#{label}</th>" )
             ).evaluate( { label:item[0], key:item[1], order:item[2] } );
     } );
     var thead = "<thead><tr>" + ths + "</tr></thead>";
     
     var trs = "";
     list.show.each( function( items, index ) {
      if( !items.index ){ items.index = index + 1; }
      var tds = "";
      header.each( function( value, index ) {
       tds += "<td>" + ( items[value[1]] ? items[value[1]] : "-" ) + "</td>";
      } );
      var trsvalue = { c1    :( index % 2 ) ? "odd" : "even"
                     , c2    :list.movies[items.name] ? " play" : " download"
                     , omover:"this.className += \" omo\";"
                     , omout :"this.className = this.className.replace(/ omo/g, \"\");"
                     , oc    :"action( this );", id:items.name
                     };
      trs +=  ( new Template( "<tr class='#{c1} #{c2}' onclick='#{oc}'"
                            + "onmouseover='#{omover}' onmouseout='#{omout}' id='#{id}'>" )
              ).evaluate( trsvalue ) + tds + "</tr>";
     } );
     var tbody = "<tbody>" + trs + "</tbody>";
     
     $( "target" ).innerHTML = "<table>" + thead + tbody + "</table>";
    }
    
    refreshImageTable = function() {
     var trs = "<tr>";
     var tds = "";
     list.show.each( function( items, index ) {
      if( !( index % 5 ) ) {
       trs += tds + "</tr>";
       tds = "<tr>";
      }
      items.state = list.movies[items.name] ? "playing" : "now";
      tds += ( new Template( "<td  id='#{name}' align='center' class='#{state}' onclick='action( this )'>"
             + "<img src='#{src}' title='#{title}\n再生:#{play} コメント:#{comment}' /></td>" )
             ).evaluate( items );
       if( index == list.show.length - 1 ) {
        trs += tds + "</tr>";
       }
     } );
     var tbody = "<tbody>" + trs + "</tbody>";
     $( "target" ).innerHTML = "<table>" + tbody + "</table>";
    }
    
    searchFlvFiles = function() {
     delete list.movies;
     list.movies = {};
     
     var fs = new ActiveXObject( "Scripting.FileSystemObject" );
     var files = new Enumerator( fs.GetFolder( pathOfDownload ).Files );
     while( !files.atEnd() ) {
      if( files.item().Name.match( /((sm|ax)\d+).*\.flv$/ ) ) {
       list.movies[RegExp.$1] = files.item();
      }
      files.moveNext();
     }
    }
    
    execBuildupCommand = function( argument )
    {
     var shell = new ActiveXObject( "WScript.Shell" );
     shell.Run( "\"" + pathOfNicoPlayer + "\\NicoPlayer.exe\" " + argument + " -inactive", 0, true );
     shell = null;
    }
    
    playingBefore = undefined;
    action = function( node ) {
     var movieName = node.id;
     if( list.movies[movieName] ) {
      if( playingBefore ) {
       playingBefore.className = playingBefore.className.replace( / playing/g, "" );
      }
      node.className += " playing";
      playingBefore = node;
      execBuildupCommand( "\"" + list.movies[movieName].Path + "\"" );
     } else {
      node.className += " now";
      execBuildupCommand( "http://www.nicovideo.jp/watch/" + movieName );
     }
    }
    
    sort = function( key, order ) {
     with( list ) {
      if( key == lastSortKey ) {
       show.reverse();
      } else {
       show = show.sortBy( function( items ) {
        var value = items[key] + "";
        if( key == "title" ) {
         return value;
        }
        value = parseInt( value.gsub( "[^0-9]", "" ) )
        return ( order == "desc" ) ? value : -value;
       });
       lastSortKey = key;
      }
      refreshTable();
     }
    }
   </script>
  </head>
  <body>
   <div id="display">JavaScriptを有効にしてください。</div>
   <table id="controller">
   <tr><form onsubmit="search.exec();return false;"><td>
    <input type="text" id="keyword" value="初音ミク">
    <select id="sort">
     <option value="">投稿日時が新しい</option>
     <option value="order=a">投稿日時が古い</option>
     <option value="sort=v" selected>再生が多い</option>
     <option value="sort=v&order=a">再生が少ない</option>
     <option value="sort=n">コメントが新しい</option>
     <option value="sort=n&order=a">コメントが古い</option>
     <option value="sort=r">コメントが多い</option>
     <option value="sort=r&order=a">コメントが少ない</option>
    </select>
    <input type="submit" value="検索" />
    <!--<button onclick="refreshTable();">再表示</button>-->
   </td></form><form onsubmit="mylist();return false;"><td>
    <input type="text" id="mylistkeyword" value="2949389/2632878" />
    <input type="submit" value="マイリスト" />
   </td></form><form onsubmit="ranking();return false;"><td>
    <select id="rsort">
     <option value="view">再生</option>
     <option value="res">コメント</option>
     <option value="mylist" selected>マイリスト</option>
    </select>
    <select id="rspan">
     <option value="newarrival">新着</option>
     <option value="daily" selected>本日</option>
     <option value="weekly">週間</option>
     <option value="monthly">月間</option>
     <option value="total">合計</option>
    </select>
    <select id="rgenre">
     <option value="all">すべて</option>
     <option value="music" selected>音楽</option>
     <option value="game">ゲーム</option>
    </select>
    <input type="submit" value="ランキング" />
   </td></form></tr>
   </table>
   <table id="selector" cellspacing="0" style="border:solid 1px #ccc; border-bottom:0px"><tr>
    <td id="rstring" class="activet" width="50%" align="center" style="cursor:pointer;" onclick="refreshTable('string');">一覧</td>
    <td id="rimage" align="center" style="cursor:pointer;" onclick="refreshTable('image');">画像一覧</td>
   </tr></table>
   <div id="target"></div>
  </body>
 </html>

**ローカルファイルを検索し表示
最上部のテキストボックスにキーワードを入力してTabキーを押すと、ローカルファイルを検索しマッチするファイルをリストアップします。お好きなファイルをクリックして再生してください。onchangeではなくonkeyupを使うとインクリメンタル検索になるのですが、このロジックだと重すぎて実用的ではないのでやめました。
 <hta:application maximizebutton="no" selection="yes"
                  navigable="no" scroll="yes" singleinstance="yes"/>
 <html>
  <head>
   <meta http-equiv="MSThemeCompatible" content="yes">
   <style>
    ul { list-style-type:none; margin:1px; }
    li { cursor:pointer; width:100%; border:3px double; margin:3px; font-size:12px }
   </style>
   <script type="text/javascript" src="prototype.js"></script>
   <script type="text/javascript">
    var pathOfDownload = "ダウンロードパス"; // ex) D:\\Download
    var pathOfNicoPlayer = "NicoPlayerインストールパス";
    
    var localFlvFiles;
    
    $_ = function( target, key ) {
     return $A( target.getElementsByTagName( key ) );
    }
    $_A = function( target, key ) {
     return target.getAttribute( key );
    }
    
    onLoad = function( link ) {
     resizeTo( 500, 800 );
     showList();
    }
    
    showList = function() {
     searchFlvFiles();
     
     // 検索
     var keyword = $F( "keyword" );
     if( keyword ) {
      localFlvFiles = localFlvFiles.findAll( function( file ) {
       return RegExp( keyword, "i" ).test( file.Name );
      } );
     }
     
     // リストクリア
     var ul = $( "target" );
     $A( ul.childNodes ).each( function( child ) {
      ul.removeChild( child );
     } );
     
     // リスト追加
     localFlvFiles.each( function( file, index ) {
      var li = document.createElement( "li" );
      li.setAttribute( "onclick", new Function( "play( \'" + index + "\' );" ) );
      file.Name.match( /(.*)\.flv$/ );
      var text = document.createTextNode( RegExp.$1 );
      li.appendChild( text );
      ul.appendChild( li );
     } );
    }
    
    searchFlvFiles = function() {
     if( !localFlvFiles ) {
      localFlvFiles = $A();
     } else {
      localFlvFiles.clear();
     }
     
     var fs = new ActiveXObject( "Scripting.FileSystemObject" );
     var files = new Enumerator( fs.GetFolder( pathOfDownload ).Files );
     while( !files.atEnd() ) {
      if( files.item().Name.match( /(sm\d+).*\.flv$/ ) ) {
       localFlvFiles.push( files.item() );
      }
      files.moveNext();
     }
    }
    
    execBuildupCommand = function( argument )
    {
     var shell = new ActiveXObject( "WScript.Shell" );
     shell.Run( "\"" + pathOfNicoPlayer + "\\NicoPlayer.exe\" " + argument, 0, true );
     shell = null;
    }
    
    play = function( index ) {
     execBuildupCommand( "\"" + localFlvFiles[index].Path + "\"" );
    }
   </script>
  </head>
  <body onload="onLoad();">
   <input type="text" id="keyword" onchange="showList();" />
   <ul id="target" />
  </body>
 </html>

**マイページに登録されているうち、ダウンロード済みアイテムのプレイリストを作成し開く
ソースファイルをメモ帳などに貼り付け、拡張子(.js)で保存してください。
pathOfNicoPlayerとpathOfDownloadをそれぞれの環境にあったパスに変更してください。
使う時はクリップボードにマイページのアドレス(http://~/0000000/000000:省略不可)を
コピーしてダブルクリックしてください。
またNicoPlayerのプレイリストウィンドウが表示されていれば、自動的に開きます。
 // 環境設定
 var pathOfNicoPlayer = "NicoPlayerのインストールパス(パスセパレータ \\)";
 var pathOfDownload = "動画ファイルのダウンロードパス(同上)";
 
 // クリップボードからマイページのアドレスを取得
 var ieObject = new ActiveXObject( "InternetExplorer.Application" );
 ieObject.Navigate( "about:blank" );
 while ( ieObject.Busy ) {
  WScript.Sleep( 100 );
 }
 var addressOfMypage = ieObject.Document.parentWindow.clipboardData.getData( "text" );
 ieObject.Quit();
 
 // マイページアドレスが取得できなかった場合入力ウィンドウを表示(Excelのインストールが必要)
 if( !addressOfMypage.match( /.*\/([0-9]+)\/([0-9]+)/ ) ) {
  var excelObject = WScript.CreateObject( "Excel.Application" );
  if( excelObject != null )
  {
   addressOfMypage  = excelObject.InputBox( "マイページのアドレスを入力してください" );
   excelObject.Quit();
  }
 }
 
 // Msxml2(IE6標準)によりマイページのGETリクエスト送出
 var httpObject = WScript.CreateObject( "Msxml2.XMLHTTP" );
 httpObject.onreadystatechange = function()
 {
  if( httpObject.readyState == 4 )
  {
   getRequestPage( httpObject );
  }
 }
 // open( , , false )は同期指定(さもないと取得前にプログラムが終了する)
 httpObject.open( "GET", addressOfMypage, false );
 httpObject.send( "" );
 
 function getRequestPage( httpObject )
 {
  // マイページのテキストを検索しID(sm[0-9]+)をリストアップ
  var requestPageText = httpObject.responseText;
  var mypageIdList = requestPageText.match( /sm[0-9]+/g );
  if( mypageIdList == null ) {
   return; // IDが見つからず
  }
  
  // ダウンロードフォルダを検索し.flvファイルをIDに基づいてリストアップ
  var filesHash = {};
  var fsoObject = WScript.CreateObject( "Scripting.FileSystemObject" );
  var filesCollection = fsoObject.GetFolder( pathOfDownload ).Files;
  for( var file = new Enumerator( filesCollection ); !file.atEnd(); file.moveNext() ) {
   var fileName = file.item().Name;
   if( fsoObject.GetExtensionName( fileName ) == "flv" ) {
    filesHash[fileName.match( /sm[0-9]+/ )] = file.item().Path;
   }
  }
  
  // マイページのIDとローカルファイルを紐付けプレイリスト形式にする
  var newPlaylistText = "", newDownloadListText = "";
  for( var i = 0; i < mypageIdList.length; i += 2 ) {
   if( filesHash[mypageIdList[i] ] != undefined ) {
    newPlaylistText += filesHash[mypageIdList[i] ] + "\n";
   }
  }
  
  // プレイリストファイル(.m3u)に落とす
  addressOfMypage.match( /.*\/([0-9]+)\/([0-9]+)/ );
  var newPlylistFileName = RegExp.$1 + "_" + RegExp.$2 + ".m3u";
  // OpenTextFile( , 2, true )の2は書出指定(読込1・追記8)、trueは新規作成あり
  var pathOfNewPlaylistFile = pathOfNicoPlayer + "\\" + newPlylistFileName;
  var newPlaylistFile = fsoObject.OpenTextFile( pathOfNewPlaylistFile, 2, true );
  newPlaylistFile.Write( newPlaylistText );
  newPlaylistFile.Close();
  
  // NicoPlayerが.m3uファイルのD&Dに対応すると、以下の全ては次の1行になります
  // shellObject.Run( "\"" + pathOfNicoPlayer + "\\NicoPlayer.exe\" \"" + pathOfNewPlaylistFile + "\"" );
  
  // プレイリストファイルパスをクリップボードへコピー
  var ieObject = new ActiveXObject( "InternetExplorer.Application" );
  ieObject.Navigate( "about:blank" );
  while ( ieObject.Busy ) {
   WScript.Sleep( 100 );
  }
  ieObject.Document.parentWindow.clipboardData.setData( "text", pathOfNewPlaylistFile );
  ieObject.Quit();
  
  // NicoPlayerのプレイリストウィンドウに登録する
  var shellObject = WScript.CreateObject( "WScript.Shell" );
  shellObject.AppActivate( "NicoPlayer - プレイリスト" );
  WScript.Sleep( 100 );
  shellObject.SendKeys( "^O" );
  WScript.Sleep( 100 );
  shellObject.SendKeys( "^V" );
  WScript.Sleep( 100 );
  shellObject.SendKeys( "%O" );
 }

**プレイリストウィンドウにプレイリストファイルをドラッグ&ドロップする(Cランタイム使用)
使い勝手向上のためぜひともD&Dを実装したかったが、スクリプトのみでは実装できなかった。
WindowsAPIをVBAでラップすれば可能だが、あまりに煩雑なので断念した。

[マイページに登録されているうち、ダウンロード済みアイテムのプレイリストを作成し開く]の
\// NicoPlayerが.m3uファイルのD&Dに対応すると、以下の全ては次の1行になります
以下を次のように置き換える。
 var shellObject = new ActiveXObject( "WScript.Shell" );
 shellObject.Run( "\"ランタイム名.exe\" \"CWndPlayList\" \"NicoPlayer - プレイリスト\" \"" + pathOfNewPlaylistFile + "\"", 0 );
 shellObject = null;
ランタイム(正確には違うが)のコードは以下の通り。
開発環境は[[Microsoft公式>http://www.microsoft.com/japan/msdn/vstudio/express/visualc/usingpsdk/]]を参考にしてください。
 #define STRICT
 #include <windows.h>
 #include <cstring>
 
 // DnD操作におけるOS領域のメモリ構造定義
 typedef struct drop_files{
  DWORD pFiles;
  POINT pt;
  bool fNC;
  bool fWide;
 } DropFiles;
 
 int main( int argc, char *argv[] )
 {
  // パラメータが3個([0]は実行ファイルのパス)未満なら終了
  if( argc < 4 ) {
   return 0;
  }
  
  // 指定窓が見つからなければ終了
  // ([1]:クラス名・[2]タイトル、空文字列も検索条件、無効にするにはNULL)
  HWND hWndTarget = FindWindowExA( NULL, NULL, argv[1], argv[2] );
  if( !hWndTarget ) {
   return 0;
  }
  
  // D&D操作のための情報を作成
  DropFiles df = { sizeof( DropFiles ), { 0, 0 }, false, false };
  char *file = argv[3];
  
  // OS領域のメモリリソースを確保し情報を転送
  HGLOBAL hGlobalMemory = GlobalAlloc( GHND, sizeof( DropFiles ) + strlen( file ) + 1 );
  void *p = GlobalLock( hGlobalMemory );
  memcpy( p, ( void * )&df, sizeof( DropFiles ) );
  memcpy( ( char * )p + sizeof( DropFiles ), ( void * )file, strlen( file ) + 1 );
  GlobalUnlock( hGlobalMemory );
  
  // 指定窓に通知
  PostMessageA( hWndTarget, WM_DROPFILES, ( WPARAM )hGlobalMemory, 0 );
  
  // OS領域のメモリリソースを開放
  GlobalFree( hGlobalMemory );
  
  return 0;
 }

*コメント
#pcomment()
目安箱バナー