很久沒有寫些東西了,發現不寫很久就會忘記一些技巧性的東西,然後又要翻閱一堆堆的代碼區查,還要試,很囧~~~~
前陣在做一個海外項目時第三方合作廠家一起開發個檔案傳送的東東,NND,他們只會用VC++,居然說COM也不會玩,暈死,讓我玩找視窗的遊戲,這年頭居然還有這樣的人,真的是遠古時代的。
下面是他們給我的VC++調用DEMO,要我用.NET來實現,真的很看得起我
代碼
#include <windows.h>
#include <stdlib.h>
const int AddFile = 1001;
const int DelFile = 1002;
struct FileTransferCommand
{
int type;
char srcFile[_MAX_PATH];
char dstFile[_MAX_PATH];
char fileId[1024];
};
// 接受方會檢查srcFile檔案存在和大小>0,才會成功添加
// 暫時只支援絕對路徑
int TransferFile(char* srcFile, char* dstFile, char* fileId)
{
FileTransferCommand cmd;
cmd.type = AddFile;
strcpy(cmd.srcFile, srcFile);
strcpy(cmd.dstFile, dstFile);
strcpy(cmd.fileId, fileId);
COPYDATASTRUCT cds;
cds.dwData = 0;
cds.cbData = sizeof(cmd);
cds.lpData = &cmd;
HWND hwnd = FindWindow("#32770", "Sender");
if(hwnd){
SendMessage(hwnd, WM_COPYDATA, (WPARAM)(HWND)0, (LPARAM)(LPVOID) &cds);
return 0;
}
return -1;
}
// fileId可以為"HYMSG_NOACK",所以僅僅根據fileId不夠
int TransferFileDelete(char* srcFile, char* fileId)
{
FileTransferCommand cmd;
cmd.type = DelFile;
strcpy(cmd.srcFile, srcFile);
strcpy(cmd.dstFile, "");
strcpy(cmd.fileId, fileId);
COPYDATASTRUCT cds;
cds.dwData = 0;
cds.cbData = sizeof(cmd);
cds.lpData = &cmd;
HWND hwnd = FindWindow("#32770", "Sender");
if(hwnd){
SendMessage(hwnd, WM_COPYDATA, (WPARAM)(HWND)0, (LPARAM)(LPVOID) &cds);
return 0;
}
return -1;
}
int main(){
TransferFile("d:\\GhostXP_SP3v9.0.iso", "d:\\dup2", "01010");
// TransferFileDelete("d:\\GhostXP_SP3v9.0.iso", "01010");
}
裡面自訂了一個FileTransferCommand結構體,還匯入了一個Windows的COPYDATASTRUCT結構體,這TMD .NET裡面根本沒,都是什麼什麼.H檔案裡面的。
代碼
typedef struct tagCOPYDATASTRUCT {
DWORD dwData;
DWORD cbData;
PVOID lpData;
} COPYDATASTRUCT;
這是Winuser.h裡面定義的,要用.NET實現必須把這些結構體翻譯成VC++看的懂的,因為VC++裡面就是指標、位、位元組什麼的,它就沒有管你CLR裡面struct什麼樣子,因為在C/C++中struct只是一個簡單的資料集合,甚至C的Struct不能包含函數的,一些C++代碼也難看見在Struct裡面寫函數的,而.NET裡面Struct相對很少使用,因為Struct在.NET中很像一個Class了,沒有太多約束。所以導致了Struct的失真。其實說白了就是.NET對結構體的序列化、C++是否可成功還原序列化的問題。
下面是我對上面代碼的.NET翻譯,已經運行成功,希望對大家一些寫類似代碼有協助。
代碼
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct FileTransferCommand
{
[MarshalAs(UnmanagedType.I4)]
public int type;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)]
public string srcFile;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)]
public string dstFile;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=1024)]
public string fileId;
}
//這種結構定義不知道為什麼不成功,希望有人交流下
// [StructLayout(LayoutKind.Explicit,Size=1548)]
// struct FileTransferCommand
// {
// [FieldOffset(0)] public int type;
// [FieldOffset(4)] public string srcFile;
// [FieldOffset(264)] public string dstFile;
// [FieldOffset(524)] public string fileId;
// }
//[StructLayout(LayoutKind.Sequential)]
struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
//[MarshalAs(UnmanagedType.LPStruct)]
public IntPtr lpData;
}
private void SendFile()
{
uint WM_COPYDATA = 0x004A;
FileTransferCommand cmd = new FileTransferCommand();
cmd.type = 1001;
cmd.srcFile = @"C:\Client.cs";
cmd.dstFile = @"C:\Client.cs";
cmd.fileId = @"11";
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds.dwData = (IntPtr)0;
cds.cbData = 1548;//Marshal.SizeOf(cmd);
cds.lpData = Marshal.AllocCoTaskMem(cds.cbData);
Marshal.StructureToPtr(cmd,cds.lpData,true);
//查到表單,得到整個表單
uint ParenthWnd = FindWindow("#32770", "Sender");
//判斷這個表單是否有效
if (ParenthWnd!=0)
{
//調用SendMessage方法設定其內容
SendMessage(ParenthWnd, WM_COPYDATA, (IntPtr)0, ref cds);
}
Marshal.FreeCoTaskMem(cds.lpData);
}
[DllImport("User32.dll", EntryPoint = "FindWindow")]
private static extern uint FindWindow(string lpClassName, string lpWindowName);
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(uint hWnd, uint Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);