|
Would you like to embed MS Word into your dialog or just spawn the MS Word application from your dialog?
|
|
|
|
|
open MS Word from the dialog
|
|
|
|
|
Then use ShellExecute(Ex).
|
|
|
|
|
|
Don't have much idea about it...
|
|
|
|
|
Have you considered ShellExecute() ?
"One man's wage rise is another man's price increase." - Harold Wilson
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
"You can easily judge the character of a man by how he treats those who can do nothing for him." - James D. Miles
|
|
|
|
|
Trying now...
Thanks for your help
|
|
|
|
|
I want to print a bitmap. To avoid printing small bitmap I set CScrollView mode as MM_LOMETRIC with sizes 3830x1995. I have created the bitmap and made the bitblt to the screen. There were everythig just like I want on the screen and on the print preview but when I printed the document I`ve got very bad result.
It seems to me that printer does not see a bitmap the same way as print preview does. Pay attantion that the first ractangle puts directly on the DC and memDC puts into it. Are there any ideas how to fix this mismatch between print previw and the real printing?
MFC_T_Print_1.zip[^]
void OnDraw()
{
CPen pen;
pen.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
CPen* OldPen = pDC->SelectObject(&pen);
CRect rcView;
GetClientRect(rcView);
int iClientWidth = rcView.right;
int iClientHeight = rcView.bottom;
int iMemWidth = 1900;
int iMemHeight = 950;
CDC memDC;
CBitmap memBitmap;
memDC.CreateCompatibleDC(pDC);
memBitmap.CreateCompatibleBitmap(pDC, iMemWidth, iMemHeight);
memDC.SelectObject(&memBitmap);
memDC.SetMapMode(MM_LOMETRIC);
CPen pen1;
pen1.CreatePen(PS_SOLID, 3, RGB(0, 0, 0));
memDC.SelectObject(&pen1);
CBrush brBK;
brBK.CreateSolidBrush(RGB(255, 255, 255));
memDC.SelectObject(&brBK);
RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = iMemWidth;
rc.bottom = iMemHeight;
memDC.FillRect(&rc, &brBK);
memDC.Rectangle(rc.left, rc.top, rc.right, -rc.bottom);
memDC.MoveTo(0, 0);
memDC.LineTo(1900, -950);
memDC.MoveTo(0, -950);
memDC.LineTo(200, -750);
CFont font;
font.CreateFont(
50,
0,
0,
0,
FW_NORMAL,
FALSE,
FALSE,
0,
ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS,
_T("Arial"));
memDC.SelectObject(&font);
memDC.TextOut(100, -100, _T("Hello"));
pDC->BitBlt(10, -10, iMemWidth, -iMemHeight, &memDC, 0, 0, SRCCOPY);
font.DeleteObject();
brBK.DeleteObject();
memDC.DeleteDC();
memBitmap.DeleteObject();
pen.DeleteObject();
pen1.DeleteObject();
}
void OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CSize sizeTotal;
sizeTotal.cx = 3830;
sizeTotal.cy = 1995;
SetScrollSizes(MM_LOMETRIC, sizeTotal);
}
MFC
|
|
|
|
|
You need to set the mapping mode in the actual device context where you are writing the data. In this case you need to set it into the PrinterDC to make it consistent with the screen settings, and the actual image. See Mapping Modes and Translations | Microsoft Docs[^].
|
|
|
|
|
Mapping mode (MM_LOMETRICETRIC) has been set both in OnPrepareDC() and in OnPrint(). The result is the same - we still have mismatch between print preview and the real printing.
|
|
|
|
|
The screen works on 96DPI unless you are in a DPI aware app which if you want to confirm
HDC screen = GetDC(0);
long hPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSX);
long vPixelsPerInch = GetDeviceCaps(screen,LOGPIXELSY);
So it's setup that 96 pixels = 1 inch, not in the real world but that is what 96 pixel represents on screen
When you map it to 0.1mm per device space 25.4mm = 1 inch so 254 pixels now = 1 inch
Now the same works for the resolution of your printer depending on it's resolution
So lets say you are printing at 150dpi on the printer so when you set it to 0.1mm per device unit
1500 pixels = 1 inch on the printer
Normallly the printer select dialog goes close because it knows the screen is 96DPI and it knows what the
printer DPI is but you have messed about with the modes and thrown it out by a fair bit.
It's usually pretty close all by itself
Anyhow the scaling is easy .... correct size = size * effective Printer DPI / effective Screen DPI;
When you select the printer you can get it's DC and pass it into the code above and get it's hPixelsPerInch
and vPixelsPerInch just as you did the screen. Hence you can work out the scale.
In vino veritas
modified 12-Sep-18 13:16pm.
|
|
|
|
|
Thak you for the answer but there is a problem with the bitmap that is inscribed in the ractangle.
If you look at the print preview - you will see this bitmap well. But if you print the real page you will see that ractangle is printed perfectly but the bitmap (inscribed into ractangle) was cut from the right side and the bottom.
If there was a problem with dpi we would have problems both with the ractangle and with the bitmap.
Print preview: Preview[^]
Real print: Printed page[^]
|
|
|
|
|
And there is nothing surprising about that you only made your DC a fixed size based on screen,
Rough guess your printer is running at 300 DPI, confirm what resolution you have on printer?
let me jog your memory with your memory bitmap/DC (which matches the screen)
===> memBitmap.CreateCompatibleBitmap(pDC, iMemWidth, iMemHeight);
then you only transfer that screen size
====> pDC->BitBlt(10, -10, iMemWidth, -iMemHeight, &memDC, 0, 0, SRCCOPY);
Those sizes are in screen pixels the printer DC is different to iMemWidth, iMemHeight pixels,
It is hardly surprising you only get the top left corner, it is telling you the same thing
Remember the sizes on the transfer are in the DC pixels of the DC you use for the function.
You have pDC vs memDC and those are not the same DPI.
You would either need to StretchBlt or get the printer DC and work out the size to make the memory
bitmap that size because it has a different DPI.
If you can set the printer to 100 DPI which is as close to 96 DPI you will get close to what you want .
In vino veritas
modified 13-Sep-18 7:21am.
|
|
|
|
|
Nice idea but
I tried to make different Width and Height for display and printer. It broke Print Preview[^].
But when I`ve printed document the result was the same[^] .
int iMemWidth = 1900;
int iMemHeight = 950;
...
if (pDC->GetDeviceCaps(TECHNOLOGY) == DT_RASDISPLAY)
{
pDC->BitBlt(10, -10, iMemWidth, -iMemHeight, &memDC, 0, 0, SRCCOPY);
}
else if (pDC->GetDeviceCaps(TECHNOLOGY) == DT_RASPRINTER)
{
pDC->BitBlt(10, -10, 3830, -1950, &memDC, 0, 0, SRCCOPY);
}
Here is the source code:
MFC_T_Print_LOMETRIC.zip[^]
|
|
|
|
|
You aren't getting that memory DC's are basically free you aren't limited to just one and why they exist
Lets see if I can make you understand.
This stuff is only important for bitmaps you can print text all day and never need to know this stuff
1.) When you print bitmaps you make a new memory DC to match the printer not the screen!!!!
HDC SecondDC = CreateCompatibleDC( >>> PrinterDC <<<);
2.) Put your image on the memory DC and you use it to print .. just like you did the screen DC
3.) Now print it.
4.) Now you destroy the memory DC that matches the printer you are done with it.
At no point in that did I change or alter your screen bitmap/DC
What you aren't grasping is why you need a memory DC .. so lets deal with that because it is important.
So a true device DC may have a different planes and colour layout to your image and if that was done
at a driver level, every driver would have to know how to deal with every colour format. So they don't
do that the driver generally knows exactly one colour format usually RGB. The memory context is the
thing that knows all the different formats and is essentially device independent. So when you want to
print what a bitmap what you want is a memory context that matches the PRINTER DC not the screen.
That is all covered here .. I want you to carefully read the paragraph that starts with
"The original bitmap in a memory DC is simply a placeholder"
Memory Device Contexts | Microsoft Docs[^]
Now here is a tutorial on bitmap printing I want you to go to Part 9
https://www.dreamincode.net/forums/topic/261009-bitmap-printing-tutorial-in-c-win32/
I want you to take particular note of lines 9 to 13 which does this
prn = GetPrinterDC(hwnd);
cxpage = GetDeviceCaps (prn, HORZRES);
cypage = GetDeviceCaps (prn, VERTRES);
hdcMem = CreateCompatibleDC(prn);
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap);
If you understood the above you will understand what they are doing but lets walk thru it
1.) They got the printer DC because that is our device NOT the screen
2.) They got the width and height of the printer from that DC.
3.) They made a memory DC to the printer DC to transfer the image onto (printer DC not screen DC)
4.) They selected the bitmap you want to print to the memory context so it initializes how
to convert the bitmap for the printer.
Then they will transfer all the image and stuff onto the memory DC, then they will copy it to
the printer and then they will throw the memory context away it isn't needed anymore.
The important part here is the memory context that matches the printer is the right scale
and it has the right colour plane organization and it has nothing to do with your display
memory context which is dangling around elsewhere in your code.
In vino veritas
modified 13-Sep-18 11:47am.
|
|
|
|
|
Hi, I met a thread synchronization scenario in a small code.
if (rcvd == true)
{
read rcv_buffer
...
rcvd = false;
}
dataCB(int ch_id, char *buf, int len, char stat)
{
rcvd = true;
receivenotify(chid, rcv_buffer, sizeof(rcv_buffer), dataCB,0);
}
here, rcvd = false in task A, can't stop task B produce data. how can I let task A, B synchronized.
add if (rcvd == false) in task B before receivenotify()? is that a dead lock ?
Thanks
|
|
|
|
|
That's not how to synchronize threads.
You should be using Events. See Using Event Objects | Microsoft Docs[^]
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
It's a rare C program, no Events
|
|
|
|
|
What is a "rare C program?"
Is this on Windows?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
No, its on a 32 bit micro controller, no OS.
|
|
|
|
|
Then you haven't threads, have you?
Are you talking about interrupts?
|
|
|
|
|
no, no interrupts, it's a simple scheduler using while(1).
and one cycle is 10 ms , one cycle is 5 ms.
task A in 10 ms cycle, task B in 5 ms cycle.
|
|
|
|
|
But have you threads? Microcontrollers usually have not.
|
|
|
|
|
You called this thread but you describe these as tasks and I read your other responses ... so I am assuming this is a task switcher.
So I am guessing you are on a pre-emtive task switcher that is running multiple tasks.
If that is the case usually you synchronize by stopping the task switcher for switching for a short period as you have a critical section.
For example of a context switcher running off a timer interrupt, you just disable the interrupts which will stop the context switcher from switching your task out. On all context switchers there is a way to do this because at various points in the kernel they have to enter critical sections. You need to keep your time inside these sections as fast as you possibly can.
Now if it is going to take to long you need to use locks. They start simple and grow in complexity as you want different things.
Even on a basic task switcher it should have a semaphore because they are so easy to define or you can make one just using a volatile int.
typepdef volatile int semaphore;
The volatile is important because you are going to end up looping around reading the same address. You need to make sure the compiler doesn't optimize that to only reading it once and using the old value for each of the check loops. It must read the memory location each and every time.
To enter a semaphore locked area generally you will make a call to something called a name like semaphore_inc or semaphore_pend.
What that will do is make sure you have single aquire on the semaphore, if you don't it will sleep your task it will basically be doing this
void semaphore_inc (semaphore* sem)
{
disable context switcher;
while (*sem != 0)
{
enable context switcher;
sleep(1);
disable context switcher;
}
*sem++;
enable context switcher;
}
The disable and enable context switcher will be simple disable and enable interrupt opcodes on a simple timer interrupt system up to a small piece of code on more advanced switchers. What is important is do you get what happens with your task getting sleeped unless it has solo access to the semaphore. The 1 will be the minimum unit of time on the task switcher until your task can be woken up. It's non blocking because the sleep call will activate the next task to run (because you can't and so you give up your timeslice) and it will come back to you sometime later on another context switch. The moment you set the semaphore any other task trying to enter would have the same happen to it because they would ask for the aquire in the same way. You can see it is important the context switcher get turned off while various parts of the test are done, you don't want to be pre-emptively switched out while you are testing.
Now once you have finished you call something like semaphore_dec, or semaphore_release which will set the semaphore back to zero again turning off the context switcher where it needs. Once you exit other tasks may enter or they will wake from a sleep and find they can go in if they were trying to aquire lock. If you have to write the code for the release it is a really simple code
void semaphore_dec (semaphore* sem)
{
disable context switcher;
*sem--;
enable context switcher;
}
So it ends up like this taskACall and taskBCall can never run at same time but they are non blocking. A task waiting to aquire the lock gives up it's timeslice to other tasks which will include the task currently in the locked area. Eventually the task in the locked area will come out and the waiting task will be able to enter but will lock the original task from re-entering until it leaves.
semaphore sem = 0;
void taskACall (void)
{
semaphore_inc(&sem);
.... // do task A code
semaphore_dec(&sem);
}
void taskBCall (void)
{
semaphore_inc(&sem);
.... // do task B code
semaphore_dec(&sem);
}
Now some CPU's and some systems have semaphores inbuilt into the MMU and C11 added atomics as a standard #include <stdatomic.h>.
So on different systems if you have to add the behaviour yourself there is a standard way to do it.
Without knowing more specifics that is about all I can tell you.
In vino veritas
modified 11-Sep-18 5:03am.
|
|
|
|
|
Thank you very much for the answer.
But the C program is in an embedded device, it's not a pre-emptive task environment, just a forever loop cycle, in which, some functions be called in 10 ms cycle, some functions be called in 5 ms cycle.
each cycle I called it a task.
The structure like a simple scheduler using while(1) loop.
Task A (or Cycle A) is a 10 ms cycle, and Task B is a 5 ms cycle, just use a counter to implemented the 10 ms , 5 ms cycle, like
while(1)
{
count ++;
if (count == 5)
{
task B be called
}
if (count == 10)
{
count = 0;
task A be called.
}
}
Thanks
|
|
|
|
|