Kingron 最好具体的代码贴出来。我到不了delphibbs

解决方案 »

  1.   

    难!
    是不是PE里面的Base Address有问题?
      

  2.   

    我猜想可能是ImageBase的问题?反正搞不清楚!
    ///**************下面是DFW的贴子***********************
    问题:Exe文件输出函数,重新启动Windows,启动默认打印机管理程序 ( 积分:99, 回复:8, 阅读:67 )
    分类:系统相关 ( 版主:luyear, zyy04 )  
    来自:qdyoung, 时间:1998-12-27 16:30:00, ID:96123 [显示:小字体 | 大字体]  
    1.在Delphi编写的Exe文件中输出函数,编译通过,但在另一个程序中无法
    调用。如果把Exe改成DLL,则一切正常。Why? 像User.exe和Gdi.exe
    (16位)就可以输出。2. 在关闭系统对话框中选择重新启动计算机时按住Shift键可以只重新
    启动Windows,如何程序实现。ExitWindows(EW_RESTARTWINDOWS,0)不行。3. 为默认打印机创建一个快捷方式后,用ShellExecute运行可以启动默认
    打印机管理程序。如果不创建快捷方式,如何直接启动。提问题、看问题都艰难,所以都写在上面了。还好现在有EMail服务,要是能
    通过EMail提问题就好了。 
     
    来自:O_O, 时间:1998-12-27 20:34:00, ID:96139 
    1.不知道你的编写exe文件是什么意思?象user.exe和gdi.exe 其实是dll文件,只
    不过扩展名为exe罢了,你还是按dll的方式来编,至于生成的dll文件扩展名随你怎么
    取,只要调用时用上全称(带扩展名)就可以了.
     
     
    来自:O_O, 时间:1998-12-29 20:35:00, ID:96285 
    2.以下是来自inprise news group 对该问题的回答:
    32-bit programs can't do that - they can only reboot the system.
    Microsoft recommends writing a small 16-bit program that restarts
    Windows and running that program from your 32-bit program.
     
     
    来自:qdyoung, 时间:1998-12-30 18:32:00, ID:96357 
    1. 我有个大的可执行(Exe)文件,其中有一个对话框想在另一个程序(Exe)中
    使用。使用DLL可以,当我的软件就得多出一个文件,我希望整个软件文件
    少些(洁癖,:),这样容易维护。我现在想被调用Exe支持命令行,另一个程序
    直接运行它就是。除此还有其它办法吗?使用OLE?就是开销(?)太大(?),
    划不着。2. 我写了个16位Exe确实可以。但Windows 95怎么实现呢,有没有现成的16位
    Exe文件呢。我在32位程序中通过Thunk技术调用User.exe中的ExitWindows导致
    关机,Why? Delphi的ExitWindows调用的是ExitWindowsEx.
     
     
    来自:O_O, 时间:1998-12-30 19:58:00, ID:96359 
    1.我觉得你这样的思路不太好,如果你的二个程序共用一些资源如对话框,不如把它们
    放到dll里,虽然多一些文件,但维护会更容易,程序也清晰许多,我不记得exe可以象
    dll一样输出函数,感觉不可能.
    2.为什么不在32位的程序里掉用那个16位的程序呢?既然M$都那样建议了.具体的原因
    可能只有问m$去了.
    3.据说有个TManager的控件可以将win95当一个DDE server来调用,不知到谁有,
    因为不关心,我没下载用过,也忘了在那里了.
     
     
    来自:qdyoung, 时间:1998-12-30 22:58:00, ID:96371 
    2. 我想知道Windows 95是怎么做的,有没有现成的16位Exe文件,或哪个文件
    有这个功能,用什么命令行。在16位程序中调用ExitWindows,与在32位程序中
    使用Thunk调用,同样的参数怎么结果不一样。而Windows98之类仍有大量的16
    代码,大量地要使用Thunk。 
     
    来自:qdyoung, 时间:1999-1-12 12:42:00, ID:97717 
    斑竹应该把分数还给我:
    1. Exe可以调用Exe的输出,不知道以前怎么一直试都不行, 现在一部到位:
    program TestExe; //输出函数的Exeuses
      Windows;procedure Test(p: PChar); export; stdcall;
    begin
      MessageBox(0, p, 'Test', MB_OK);
    end;exports
      Test;begin
    end.procedure TForm1.Button1Click(Sender: TObject); //另一APP中调用
    var
      lib: THandle;
      Test: procedure(p: PChar); stdcall;
    begin
      lib := LoadLibrary('TestExe.exe');
      if lib = 0 then
        ShowError('Cannot load the module')
      else
      begin
        @Test := GetProcAddress(lib, 'Test');
        if @Test = nil then
          ShowError('Cannot GetProcAddress')
        else Test('This is a test');
        FreeLibrary(lib);
      end;
    end;2. 感谢http://www.experts-exchange.com/Q.10115419, 以下代码RestartWindows可以实现:
    {$StackFrames On}  //QT_Thunk needs a stack frame, Thunking call to 16-bit USER.EXE. The ThunkTrash argument allocates space on the stack for QT_Thunk
    function LoadLibrary16(LibraryName: PChar): THandle; stdcall; external kernel32 index 35;
    procedure FreeLibrary16(HInstance: THandle); stdcall; external kernel32 index 36;
    function GetProcAddress16(Hinstance: THandle; ProcName: PChar): Pointer; stdcall; external kernel32 index 37;
    procedure QT_Thunk; cdecl; external kernel32 name 'QT_Thunk';
    var
      hInst16: THandle;
      GFSR: Pointer;
    function RestartWindows: WordBool;
    var
      ThunkTrash: array[0..$20] of Word;
      dw: DWord;
      w: Word;
    begin
      if Win32Platform = VER_PLATFORM_WIN32_NT then
      begin
        Result := False;
        Exit;
      end;
      ThunkTrash[0] := hInst16; //Prevent the optimizer from getting rid of ThunkTrash
      hInst16 := LoadLibrary16('user.exe');
      if hInst16 < 32 then
        raise Exception.Create('Cannot load USER.EXE');
      FreeLibrary16(hInst16); //Decrement the usage count. This doesn't really free the library, since USER.EXE is always loaded
      GFSR := GetProcAddress16(hInst16, 'ExitWindows'); //Get the function pointer for the 16-bit function in USER.EXE
      if GFSR = nil then
        raise Exception.Create('Cannot get address of ExitWindows');
      dw := EW_RestartWindows;
      w  := 0;
      asm  //Thunk down to USER.EXE
        push dw           { push arguments }
        push w
        mov edx, GFSR     { load 16-bit procedure pointer }
        call QT_Thunk     { call thunk }
        mov Result, ax    { save the result }
      end;
    end;
    {$StackFrames Off}3. 感谢http://www.experts-exchange.com/Q.10115433, 以下代码ShowPrintSpool可以实现:
    function ExecuteContextMenuCommand(hParent: THandle; sf: IShellFolder; childPidl: PItemIDList;
      verb: string = ''; propPage: string = ''; pidlCount: UInt = 1): Boolean;
    var
      cm, cm2, cm3: IContextMenu;
      ici: TCMInvokeCommandInfo;
      pop : HMenu;
      c: Cardinal;
    begin
      Result := False;
      if sf.GetUIObjectOf(hParent, pidlCount, childPidl, IID_IContextMenu,nil, Pointer(cm)) <> NOERROR then Exit;
      try
        cm2 := cm as IContextMenu2;
        cm := cm2;
        try
          cm3 := cm as IContextMenu3;
          cm := cm3;
        except
        end;
      except
      end;
      ZeroMemory(@ici, sizeOf(ici));
      with ici do
      begin
        cbSize := sizeOf(TCMInvokeCommandInfo);
        fMask := CMIC_MASK_FLAG_NO_UI;
        hWnd := hParent;
        lpVerb := PChar(verb);
        lpParameters := PChar(propPage); //'Settings';
        nShow := SW_SHOW;
      end;
      if verb <> '' then
        Result := cm.InvokeCommand(ici) = NOERROR
      else
      begin
        pop := CreatePopupMenu;
        try
          if Succeeded(cm.QueryContextMenu(pop, 0, 1, $7FFF, CMF_DEFAULTONLY)) then
          begin
            c := GetMenuDefaultItem(pop, 0, 0);
            if c <> 0 then
            begin
              ici.lpVerb := MakeIntResource(c - 1);
              Result := cm.InvokeCommand(ici) = NOERROR;
            end;
          end;
        finally
          DestroyMenu(pop)
        end;
      end
    end;function PidlToStr(sf: IShellFolder; childPidl: PItemIDList): string;
    var
      sr: _StrRet;
    begin
      Result := '';
      if (sf = nil) or (childPidl = nil) then Exit;
      sr.uType := STRRET_CSTR;
      if sf.GetDisplayNameOf(childPidl,SHGDN_NORMAL,sr) = NOERROR then
        case sr.uType of
          STRRET_CSTR   : Result := string(sr.cStr);
          STRRET_OFFSET : Result := string(PChar(Cardinal(childPidl) + sr.uOffset));
          STRRET_WSTR   : Result := string(sr.pOleStr);
        end;
    end;function DefaultPrinterDevice: string;
    var
      Device, Driver, Port: array [0..255] of Char;
      Mode: THandle;
    begin
      Device := '';
      with Printer do
        if Printers.Count > 0 then
          GetPrinter(Device, Driver, Port, Mode);
      Result := Device;
    end;procedure ShowPrintSpool;
    var
      pidl1, pidl2: PItemIDList;
      sf1, sf2: IShellFolder;
      malloc: IMalloc;
      el: IEnumIDList;
      c: Cardinal;
      sDefaultPrinter: string;
    begin
      if (SHGetSpecialFolderLocation(INVALID_HANDLE_VALUE, CSIDL_PRINTERS, pidl1) = NOERROR) and
        (SHGetMalloc(malloc) = NOERROR) then
        try
          if (pidl1^.mkid.cb <> 0) and (SHGetDesktopFolder(sf1) = NOERROR) and
            (sf1.BindToObject(pidl1, nil, IID_IShellFolder, Pointer(sf2)) = NOERROR) and
            (sf2.EnumObjects(Application.Handle, High(Cardinal), el) = NOERROR) then
          begin
            sDefaultPrinter := DefaultPrinterDevice;
            el.Reset;
            while el.Next(1, pidl2, c) = NOERROR do
            begin
              if PidlToStr(sf2, pidl2) = s